Основы AJAX: Передача данных с помощью XMLHttpRequest

Сентябрь 8, 2007 – 19:43

Здесь и далее, используя термин AJAX, мы будем иметь в виду не дословную расшифровку этой аббревиатуры (Asynchronous JavaScript and XML), а скорее обобщенную концепцию обмена данными между браузером клиента и веб-сервером без перезагрузки страницы. Для нас AJAX безусловно подразумевает JavaScript, но совсем не обязательно включает XML.

В данном цикле статей мы рассматриваем три базовых функциональных элемента, на которых основано большинство AJAX-приложений:

Передача данных с помощью XMLHttpRequest

Данный метод передачи данных прост и элегантен, а также совместим со всеми распространенными браузерами, в связи с чем закрывает подавляющее большинство потребностей обмена.

Начинается все с создания объекта XMLHttpRequest (данный код в большей части позаимствован отсюда):

function createXMLHttpRequest() {
  var xmlReq = false;
  // branch for native XMLHttpRequest object
  if(window.XMLHttpRequest) {
    try {
      xmlReq = new XMLHttpRequest();
    } catch(e) {
      xmlReq = false;
    }
  // branch for IE/Windows ActiveX version
  } else if(window.ActiveXObject) {
    try {
      xmlReq = new  ActiveXObject("Msxml2.XMLHTTP");
    } catch(e) {
      try {
        xmlReq = new  ActiveXObject("Microsoft.XMLHTTP");
      } catch(e) {
        xmlReq = false;
      }
    }
  }
  return xmlReq;
}

Мы будем вызывать эту функцию каждый раз, когда нам нужно будет получить экземпляр данного объекта. Несколько экземпляров XMLHttpRequest могут использоваться одновременно для отправки/получения данных от разных компонент на одной веб-странице.

Мы также используем эту функцию для определения AJAX-совместимости браузера клиента:

var userAgent = { };
userAgent.isAJAX  = (createXMLHttpRequest()?true:false);
userAgent.isMozilla  = (navigator.userAgent.match(/\bGecko\b/));
userAgent.isOpera  = (navigator.userAgent.match(/\bOpera\b/));
userAgent.isInternetExplorer  =
  (navigator.userAgent.match(/\bMSIE\b/) && !userAgent.isOpera);

Для обмена данными с сервером мы используем следующий метод:

function callServer(method, url, data, dataType, func, arg) {
  if (!method) method='GET';
  var xmlReq = createXMLHttpRequest();
  if(xmlReq) {
    xmlReq.onreadystatechange = function() {
      // only if xmlReq shows "loaded"
      if (xmlReq.readyState == 4) {
        func(arg, xmlReq.responseText,  xmlReq.responseXML,
             xmlReq.status, xmlReq.statusText);
      }
    };
    xmlReq.open(method, url, true);
    if (data) {
      if (!dataType) dataType='application/xml';
      if (typeof(data)!="string" && dataType.indexOf("charset=")<0
           && userAgent.isMozilla) dataType=dataType+';charset=utf-8';
           // in Mozilla XML always serialized as UTF-8
      xmlReq.setRequestHeader('Content-Type', dataType);
    }
    xmlReq.send(data);
    return false;
  }
  return true;
}

Параметры вызова:

  • method - HTTP-метод: ‘GET’, ‘POST’, … (не все браузеры поддерживают методы, отличные от GET/POST)
  • url - адрес страницы (должен быть на том же домене, что и страница, с которой идет вызов функции - это ограничение безопасности присутствует во всех основных браузерах)
  • data - данные для POST-запроса (тип данных нужно указать в параметре dataType)
  • dataType - MIME-тип данных POST-запроса (полезные варианты: ‘application/xml’, ‘application/x-www-form-urlencoded’)
  • func - функция, которая будет вызвана автоматически по завершении запроса к серверу для обработки результата; функция будет вызвана со следующими параметрами:
  • func(arg, responseText, responseXML, statusCode, statusText);
  • arg - параметр arg, который был указан при вызове callServer()
  • responseText - ответ сервера в виде текста (используется, если сервер возвращает не XML, а, к примеру, обычный HTML)
  • responseXML - объект типа XMLDocument (используется, если сервер возвращает XML)
  • statusCode - код завершения запроса (наиболее часто используемые коды: 200 - ОК, 404 - файл не найден, 401 - требуется авторизация; подробности - см. стандарт HTTP)
  • statusText - текст с описанием ошибки (его можно показать пользователю, если код завершения не равен 200)

Приведем пример использования вышеописанных функций для загрузки и отображения внешнего HTML-документа в заданном участке текущей страницы:

<script type="text/javascript">
// ... сюда необходимо скопировать все вышеописанные функции  ...
function showHTML(element, responseText, responseXML, statusCode, statusText) {
  if (typeof(element)=="string")
    element=document.getElementById(element);
  if (statusCode==200 || statusCode==201) {
    element.innerHTML=responseText;
  }
  else {
    alert("Загрузить информацию не  удалось: "
          +statusText);
  }
}
</script>
<input type="button" value="Загрузить!"
onclick="callServer(null, 'sample_doc.htm', null, null, showHTML, 'targetDiv')"/>
<div id="targetDiv">Здесь появится содержимое sample_doc.htm</div>

Ссылка на работающий пример: sample1.htm

  1. Комментарии (22) к статье “Основы AJAX: Передача данных с помощью XMLHttpRequest”

  2. Ноя 24, 2007. От handmade.

    У меня была проблема с кодировкой. Сервер выдавал sample_doc.htm в utf-8
    Исправил положение заменив sample_doc.htm на sample_doc.php с таким кодом:

    header(”Content-type: text/html; charset=windows-1251″);
    echo “Это ответ в кириллице!”

  3. Ноя 27, 2007. От edyan.

    интересно, а почему переданные параметры не видно в файле sample_doc.htm? (в моем случае php)
    можно конечно сделать так:

    callServer(null, ’sample_doc.htm?param=val’…..

    но это же не наш метод, и к тому же метод “POST” не используется.
    Что я делаю не так?

  4. Ноя 27, 2007. От admin.

    edyan,

    Если Вы хотите передать параметры в sample_doc.php, то существует два метода:

    1) callServer(’GET’, ’sample_doc.php?param=val’, null, null, func, arg);

    2) callServer(’POST’, ’sample_doc.php’, ‘param=val’, ‘application/x-www-form-urlencoded;charset=windows-1251′, func, arg);

    Чтобы второй вариант не глючил с кодировкой в Firefox, надо слегка подправить код функции callServer(). В текст статьи сейчас внесу соответствующие изменения (буквально вчера только отловил этот баг).

  5. Ноя 28, 2007. От edyan.

    в функции callServer, на мой взгляд, не хватает преобразования data к необходимому виду. вот как это сделал я (предполагается, что data является массивом):

    var post=”;
    for(id in data){
    post = post + id + “=” + encodeURIComponent(data[id]) + “&”;
    }

  6. Ноя 28, 2007. От edyan.

    забыл добавить, что далее вызов xmlReq.send идет с параметром post
    xmlReq.send(post)

    вроде вот так.

  7. Ноя 28, 2007. От admin.

    Логично. Но думается мне, что подобные преобразования лучше делать до вызова callServer(). Иначе функция утратит свою универсальность. Я, например, в качестве data передавал объект XML. Можно для удобства написать такую функцию:

    function postServer(url, data, func, arg) {
    var post=”;
    for(id in data){
    post=post+id+’='+encodeURIComponent(data[id])+’&';
    }
    return callServer(’POST’, ’sample_doc.php’, post, ‘application/x-www-form-urlencoded;charset=utf-8′, func, arg);
    }

    Обратите внимание, что encodeURIComponent() всегда использует кодировку UTF-8!

  8. Дек 4, 2007. От MrT.

    Имеется форма

    Работает как видно через POST единственное что с нее приходит это seenform=forms. А как заставить ее еще отсылать par1 и par2 вводимые пользователем на сайте ?

  9. Дек 4, 2007. От MrT.

    function getForm(fobj) {
    var str = “encode=utf8&”;
    var ft = “”;
    var fv = “”;
    var fn = “”;
    var els = “”;
    for(var i = 0;i

  10. Дек 4, 2007. От admin.

    К сожалению, WordPress, на котором в порядке эксперимента я сделал этот блог, не дает писать угловые скобки в комментариях. Мог бы просто эскейпить их, но он их удаляет. И кавычки портит.

    Извините за неудобства, но не знаю, как это исправить.

    Попробую вручную заескейпить: < и > - получилось! но геморройно…

    PS. Вот поэтому не люблю готовый “стандартный” софт.

  11. Фев 20, 2008. От MrT.

    Возник вопрос с выполнением Ява-скриптов внутри полученных ответов с сервера (responseText).

    как вариант нашол
    function EvalAJAXScripts(obj)
    {
    scripts_arr = obj.getElementsByTagName(”script”);
    for(i in scripts_arr) eval(scripts_arr[i].text);
    }

    http://www.habrahabr.ru/blog/AJAX/9063.html#habracut
    но он неработает.(

  12. Фев 21, 2008. От admin.

    Да, этот скрипт можно использовать лишь в качестве идеи. Чтобы он стал рабочим надо отлаживать по шагам. Сразу вижу одну конструкцию (.text), которая не во всех браузерах будет работать. И применять его надо не к responseText, а к responseXML.

    Вообще, если нужно выполнять скрипты, получаемые с сервера, есть куда более элегантный подход: http://web-tec.info/2007/09/09/ajax_fundamentals_script_jsonp/

  13. Янв 5, 2010. От borisovks.

    Здравствуйте, есть вопрос по этому скрипту, я сбираюсь передавать параметры в скрипт-обработчик, и задаю эти параметры переменными крпмеру:

    var param = “123″;
    И в фунции callServer добавил xmlReq.send(data+param)
    Так все работает

    Но никак не проходит такая конструкция:
    var obj = document.getElementById(’search’);
    var param = obj.value;

    В ответ от скрипта получаю “undefined”

    Тоесть я хочу извлекать передаваймеый параметр из формы на хтмл странице

  14. Янв 5, 2010. От admin.

    На всякий случай уточню, что data - это тело POST-запроса. Если вы используете POST, надо задавать соответствующий тип в dataType. Для передачи параметров методом GET добавьте их к url, а не к data (соответствующим образом закодировав).

    Другое замечание - нет никакой нужды что-то менять в функции callServer. Значение data приходит в нее извне. Вы можете заложить в data любые параметры перед обращением к callServer().

    Если obj.value равен “undefined”, значит так оно и есть. Функция callServer() никакого отношения к этому не имеет.

    Скопируйте, пожалуйста, сюда html-фрагмент, где присутствует поле формы, у которого id=”search”.

    Убедитесь также, что параметр data определен при вызове callServer.

  15. Янв 5, 2010. От borisovks.

    Так, начну по порядку.

    По поводу data я все помниаю, что это тело POST-запроса я просто для удобства параметр сделал отдельной переменной… выглядит это так:
    callServer(’POST’, ’sample_doc.php’, ’search=’, ‘application/x-www-form-urlencoded;charset=windows-1251′, showHTML, ‘targetDiv’)
    …тоесть к “search=” добавляется param но это не суть важно, просто когда я param присваиваю определеное значение, напр. var param = “123″;
    То принимающий скрипт его получает, и отсылает мне обратно.
    Но когда делаю var param = obj.value
    то обратно получаю “undefinded”

    Вот кусок кода из sample.htm:
    function getSerch() {
    var obj = document.getElementById(’search’);
    var param = obj.value;
    }

    Причем я сделал отдельный скрипт, в котором получал запросто значение из формы:
    function getText()
    {
    var obj = document.getElementById(’search’);
    var param = obj.value;
    var div = document.getElementById(’targetDiv’);
    div.innerHTML = param;
    }

  16. Янв 5, 2010. От borisovks.

    ммм, после “…” я пытался вставить хтмл код, но видимо движок блога его вырезал… попробую так:

    это после первой функции

    input type=”text” id=”search” size=”25″
    input type=”button” value=”Загрузить!”
    onclick=”getSearch(); callServer(’POST’, ’sample_doc.php’, ’search=’, ‘application/x-www-form-urlencoded;charset=windows-1251′, showHTML, ‘targetDiv’)”

    это после второй:

    input type=”text” id=”search” size=”25″
    input type=”button” value=”Получить”
    onclick=”getText()”
    div id=”target” div

    …убрал “” суть думаю осталась понятной

  17. Янв 5, 2010. От admin.

    Трудно понять, не видя кода целиком.

    Однако, функция getSerch() не выглядит законченной - переменная param в ней никак не используется, наверное не хватает “return param;” в конце.

  18. Янв 5, 2010. От admin.

    Если хотите, чтобы переменная param была доступна вне функции getSearch, определите ее снаружи.

  19. Янв 5, 2010. От borisovks.

    Дико извиняюсь, я функцию использовал на подобии процедуры :) она определена выше была, забыл это закинуть, много код изменял, и “сюда” попал такой вариант, в оригинале это выглядит так:

    var param;
    function getSearch() {
    var obj = document.getElementById(’search’);
    param = obj.value;
    }

  20. Янв 5, 2010. От admin.

    По приведенным фрагментам не могу найти ошибку. Нужен полный текст страницы, включая скрипты. Залейте куда-нибудь и пришлите ссылку.

  21. Янв 5, 2010. От borisovks.

    Черт, пока в текстах копался, сам ошибку нашел…
    Запутался в версиях файлов, у меня на сервере лежал вариант где getSearch() была после callServer() это была моя первая ошибка, которую я сам давно нашел, но забыл обновить файл на сервере, просто скрипты лежат у меня в отдельных файлах… а грешил я в основном на них. Извиняюсь за беспокойство.

  1. 2 Trackback(s)

  2. Сен 9, 2007: WEB-TEC.info » Blog Archive » Основы AJAX: Передача данных с помощью IFRAME
  3. Сен 9, 2007: WEB-TEC.info » Blog Archive » Основы AJAX: Передача данных с помощью элементов <script> (+JSONP)

Необходимо войти, чтобы оставить комментарий.