AJAX: С чего начать » Russian Ajax Community – Всё об Ajax
 


AJAX: С чего начать

В этой статье рассмотрены основные принципы работы AJAX и даны два простых примера, использующих эту технологию.

Содержание

1 Что такое AJAX?
2 Шаг 1 — Как послать HTTP запрос
3 Шаг 2 — Обрабатываем HTTP ответ
4 Шаг 3 — Простой пример
5 Шаг 4 — Работа с XML ответом

Что такое AJAX?

Ajax означает Асинхронный JavaScript и XML. В основе технологии лежит использование нестандартного объекта XMLHttpRequest(), необходимого для взаимодействия со скриптами на стороне сервера. Объект может как отправлять, так и получать информацию в различных форматах включая XML, HTML и даже текстовые файлы. Самое привлекательное в Ajax — это его асинхронный принцип работы. С помощью этой технологии можно осуществлять взаимодействие с сервером без необходимости перезагрузки страницы. Это позволяет обновлять содержимое страницы частично, в зависимости от действий пользователя.

Две особенности, которые мы рассмотрим:

* Отправление запросов серверу без перезагрузки страницы
* Работа с XML документами

Шаг 1 — Как послать HTTP запрос

Для того, чтобы послать HTTP запрос на сервер используя JavaScript, вам необходим экземпляр класса, который позволит это сделать. Такой класс впервые был введен в Internet Explorer как объект ActiveX, называемый XMLHTTP. Позже в Mozilla, Safari и другие броузеры был введен класс XMLHttpRequest, который поддерживал методы и свойства изначального объекта ActiveX от Microsoft.

В результате, чтобы создать кросс-броузерный объект требуемого класса, вы можете сделать следующее:

if (window.XMLHttpRequest) { // Mozilla, Safari, ...
http_request = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
http_request = new ActiveXObject("Microsoft.XMLHTTP");
}

(В целях наглядности код выше является немного упрощенным. Более жизненный пример будет рассмотрен в шаге 3 этой статьи)

Некоторые версии некоторых броузеров Mozilla не будут корректно работать, если ответ сервера не содержит заголовка XML mime-type. Чтобы решить эту проблему вы можете использовать вызовы дополнительных методов для переопределения заголовка полученного от сервера, если он отличен от text/xml.

http_request = new XMLHttpRequest();
http_request.overrideMimeType('text/xml');

Далее вам необходимо решить, что вы будете делать после получения ответа сервера. На этом этапе вам необходимо указать объекту, какая JavaScript функция будет обрабатывать ответ. Это делается путем присваивания свойству onreadystatechange имени JavaScript функции, которую вы собираетесь использовать:

http_request.onreadystatechange = nameOfTheFunction;

Заметьте, что после названия функции нет скобок и не указано параметров, потому что вы просто присваиваете ссылку на функцию, а не вызываете ее. К тому же, вместо указания имени функции, вы можете использовать возможность JavaScript объявлять функции на лету (так называемые «анонимные функции») и указывать действия, которые тотчас же будут обрабатывать ответ:

http_request.onreadystatechange = function(){
// какой-нибудь код
};

Далее, после того как вы объявили что будет происходить после получения ответа, вам необходимо сделать запрос. Вы должны вызвать методы класса open() и send():

http_request.open('GET', 'http://www.example.org/some.file', true);
http_request.send(null);

* Первый параметр вызова функции open() — метод запроса HTTP (GET, POST, HEAD или любой другой метод, который вы хотите использовать). Используйте методы в соответствии с HTTP стандартами; иначе некоторые броузеры (такие как Firefox) могут не обработать запрос. Информация о допустимых HTTP запросах доступна по адресу спецификации W3C
* Второй параметр — URL запрашиваемой страницы. Из соображений безопасности вы не можете запрашивать страницы сторонних доменов. Убедитесь, что вы используете одинаковое доменное имя на всех страницах, иначе вы получите ошибку 'доступ запрещен' при вызове функции open(). Типичной ошибкой при доступе к сайту через site.ru является подача запросов на www.site.ru.
* Третий параметр указывает, является ли запрос асинхронным. Если он TRUE, то выполнение JavaScript продолжится во время ожидания ответа сервера. В этом и заключается асинхронность технологии.

Параметром метода send() могут быть любые данные, которые вы хотите послать на сервер. Данные должны быть сформированы в строку запроса:

name=value&anothername=othervalue&so=on

Заметьте, что если вы хотите отправить данные методом POST, вы должны изменить MIME-тип запроса с помощью следующей строки:

http_request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

Иначе сервер проигнорирует данные отправленные методом POST.

Шаг 2 — Обрабатываем HTTP ответ

Отправляя запрос, вы указали имя функции JavaScript, обрабатывающей ответ.

http_request.onreadystatechange = nameOfTheFunction;

Давайте посмотрим, что эта функция должна делать. Во-первых, функция должна проверять статус запроса. Если значение переменной статуса 4, то это означает, что ответ от сервера получен и его можно обрабатывать.

if (http_request.readyState == 4) {
// все в порядке, ответ получен
} else {
// все еще не готово
}

Полный список значений кодов readyState такой:

* 0 (uninitialized)
* 1 (loading)
* 2 (loaded)
* 3 (interactive)
* 4 (complete)

(Источник)

Следующее, что нужно проверить — это статус HTTP-ответа. Все возможные коды можно посмотреть на сайте W3C. Для наших целей нам интересен только код ответа 200 OK.

if (http_request.status == 200) {
// великолепно!
} else {
// с запросом возникли проблемы,
// например, ответ может быть 404 (Не найдено)
// или 500 (Внутренняя ошибка сервера)
}

Теперь, после проверки состояния запроса и статуса HTTP-ответа, вы можете делать с данными, полученными от сервера, все что угодно. Есть два способа получить доступ к данным:

* http_request.responseText – возвращает ответ сервера в виде строки текста.
* http_request.responseXML – возвращает ответ сервера в виде объекта XMLDocument, который вы можете обходить используя функции JavaScript DOM

Шаг 3 — Простой пример

Давайте соберем все вместе и сделаем простой пример HTTP-запроса. Наш JavaScript запросит HTML документ test.html, который содержит текст "I'm a test." и выведет содержимое файла в диалоговом окне.


<script type="text/javascript" language="javascript">
function makeRequest(url) {
var http_request = false;
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
http_request = new XMLHttpRequest();
if (http_request.overrideMimeType) {
http_request.overrideMimeType('text/xml');
// Читайте ниже об этой строке
}
} else if (window.ActiveXObject) { // IE
try {
http_request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
http_request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
if (!http_request) {
alert('Не вышло :( Невозможно создать экземпляр класса XMLHTTP ');
return false;
}
http_request.onreadystatechange = function() { alertContents(http_request); };
http_request.open('GET', url, true);
http_request.send(null);
}
function alertContents(http_request) {
if (http_request.readyState == 4) {
if (http_request.status == 200) {
alert(http_request.responseText);
} else {
alert('С запросом возникла проблема.');
}
}
}
</script>
<span
style="cursor: pointer; text-decoration: underline"
onclick="makeRequest('test.html')">
Сделать запрос
</span>

В этом примере:

* Пользователь нажимает на ссылку "Сделать запрос" в броузере;
* Это вызывает функцию makeRequest() с параметром test.html — именем HTML файла;
* Посылается запрос, после чего (onreadystatechange) выполнение передается alertContents();
* alertContents() проверяет получен ли ответ и все ли с ним в порядке, после чего содержимое файла test.html выводится в диалоговом окне.

Вы можете попробовать пример в действии здесь, а сам тестовый файл можно посмотреть здесь.

Замечание: Строка http_request.overrideMimeType('text/xml'); вызовет ошибки в консоли JavaScript в Firefox 1.5 или более позднем, как описано в https://bugzilla.mozilla.org/show_bug.cgi?id=311724, если страница вызванная с помощью XMLHttpRequest не является правильным XML (например, если это обычный текст). На самом деле это корректное поведение.

Замечание 2: Если вы посылаете запрос не на статический XML-файл, а на серверный скрипт, возвращающий XML, то нужно установить некоторые заголовки ответа, если вы планируете сделать вашу страницу работоспособной в Internet Explorer помимо Mozilla. Если вы не установите заголовок Content-Type: application/xml, IE будет сообщать об ошибке JavaScript, 'Object Expected', после строки, где вы пытаетесь получить доступ к XML элементу. Если вы не установите заголовок Cache-Control: no-cache броузер будет кэшировать ответ и никогда не будет повторно отправлять запрос, что сделает отладку весьма «забавной».

Замечание 3: Если переменная http_request используется глобально, то конкурирующие функции, вызывающие makeRequest() могут конкурировать друг с другом, вызывая состязания. Объявление переменной http_request локально в функции и передача ее в alertContent() предотвращает состязания.

Замечание 4: При привязывании функции обратного вызова к onreadystatechange нельзя указывать аргументов. По этой причине не работает следующий код:

http_request.onreadystatechange = alertContents(http_request); // (не работает)

Таким образом, для успешной регистрации функции, вы должны передать ей аргументы косвенно через анонимную функцию или используя http_request как глобальную переменную. Вот пример:

http_request.onreadystatechange = function() { alertContents(http_request); }; //1 (одновременный запрос)
http_request.onreadystatechange = alertContents; //2 (глобальная переменная)

Первый способ позволяет делать несколько запросов одновременно, а второй используется, когда переменная http_request является глобальной.

Замечание 5: В случае ошибки взаимодействия (например, если сервер упал), при попытке доступа к переменной .status метода onreadystatechange будет сгенерировано исключение. Убедитесь, что if...then заключено в try...catch. (См. https://bugzilla.mozilla.org/show_bug.cgi?id=238559).

function alertContents(http_request) {
try {
if (http_request.readyState == 4) {
if (http_request.status == 200) {
alert(http_request.responseText);
} else {
alert('С запросом возникла проблема.');
}
}
}
catch( e ) {
alert('Произошло исключение: ' + e.description);
}
}
<strong>Шаг 4 — Работа с XML ответом</strong>

В предыдущем примере, после того как был получен ответ на HTTP-запрос мы использовали responseText запрашиваемого объекта, который содержал данные файла test.html. Теперь давайте попробуем использовать свойство responseXML.

Прежде всего, давайте создадим правильный XML документ, который мы будем запрашивать. Документ (test.xml) содержит следующее:

< ?xml version="1.0" ?>

I'm a test.

В скрипте нам всего лишь необходимо заменить строку запроса на:

...
onclick="makeRequest('test.xml')">
...

Далее в alertContents() нам нужно заменить строку alert(http_request.responseText); на:

var xmldoc = http_request.responseXML;
var root_node = xmldoc.getElementsByTagName('root').item(0);
alert(root_node.firstChild.data);

Этот код берет объект XMLDocument, возвращаемый responseXML и использует методы DOM для доступа к данным, содержащимся в документе XML. Посмотреть test.xml можно здесь, а обновленный скрипт здесь.

Чтобы узнать больше о методах DOM, посмотрите реализация DOM в Mozilla.

Источник: http://developer.mozilla.org

На сообщение “AJAX: С чего начать” комментариев: 42

  1. COBA:

    мне бы хотелось где-нибудь найти книжки на русском языке по аяксу

  2. Игрок:

    Спасибо, очень доходчиво написано.

  3. Константин:

    Спасибо, очень доходчиво написано. Только вот у меня вопрос, как нормально передать кирилицу??? Все запросы отрабатываются нормально , только вместо кирилицы непонятно что приходит, и нормально не отображается. Спасибо.

  4. Студент:

    интересненько

  5. vomm:

    Статья интересная, но.... А чем хуже javascript и iframe? Тоже можно реализовать изменение страницы без перезагрузки. Причем тока стандартными средствами. Не нужно заботиться о всяких заголовках и обеспечивать кросбраузерность.

  6. konfuze:

    > Все запросы отрабатываются нормально , только вместо кирилицы непонятно что приходит, и нормально не отображается.

    header('Content-Type: text/html; charset=windows-1251');

  7. Студент:

    Где бы поподробнее почитать о том, каким образом серверные cgi скрипты отправляют данные, которые запросил клиент, и как клиент их должен принимать?
    там что то про respontetext как то так..

  8. IceFire:

    Проблема в следующем. Когда в парамер ф-ции

    http_request.open('GET', 'http://www.example.org/some.file', true);

    ставим последним не true, а false, FireFox перестает корректно обрабатывать такой запрос.

    А мне очень надо именно так. Посоветуйте что-нить....

  9. Fry:

    > Все запросы отрабатываются нормально , только вместо кирилицы непонятно что приходит, и нормально не отображается.

    по умолчанию кодировка XML - это unicode

    поэтому то что отсылаешь перекодируй из win-1251 в utf-8 ))
    или в начале ответа пиши

  10. DeamonShan:

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

    и еще.. как вэш убрать... опишите... заголовки не помогают..

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

    хелп плиз

  11. DeamonShan:

    то есть в последнем посте ошибочка.. там

    как кэш убрать... :)

  12. koderr:

    > как кэш убрать

    "Если вы не установите заголовок Cache-Control: no-cache броузер будет кэшировать ответ и никогда не будет повторно отправлять запрос, что сделает отладку весьма «забавной»."

  13. Barzoy:

    > как кэш убрать

    В php скрипте, который выдает ответ на АЯКС запрос пропиши вот это.

    header( 'Expires: Mon, 26 Jul 1970 05:00:00 GMT' );
    header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
    header( 'Cache-Control: no-store, no-cache, must-revalidate' );
    header( 'Cache-Control: post-check=0, pre-check=0', false );
    header( 'Pragma: no-cache' );

    Код необходимо вставить перед всеми echo()

  14. masic:

    Чем копаться с кэш-контролом, ИМХО проще POST передавать.

  15. НДСник:

    to masic:
    Вы, наверное, правы - иного выхода я не нашел

  16. Андрей:

    Все выглядит достаточно привлекательно, но нужно ли это в большинстве сайтов? Я думаю нет. На крайний случай можно воспользоваться JavaScript для показа страничек без перезагрузки всего сайта. Пример: http://resheniya.com

  17. Михаил:

    Для кириллицы используйте encodeURI при отправке запроса. А ответы отправляйте в UTF-8. Это единственный способ, позволяющий на 100% избежать гемора с русским языком.

    Блин, я ж эту статью с английского переводил в свое время!
    http://developer.mozilla.org/ru/docs/index.php?title=AJAX:%D0%A1_%D1%87%D0%B5%D0%B3%D0%BE_%D0%BD%D0%B0%D1%87%D0%B0%D1%82%D1%8C&printable=yes

  18. Lenfer:

    Огромное спасибо наконецто понял что к чему ))) ... а то я уже начал думать что тупой как пробка ...

  19. wook1e:

    Крутейшая технология! Почему я раньше о ней не знал? =)
    Спасибо за подготовку статьи. GJ.

  20. trueasl:

    Спасибо. Стало намного яснее, что и как работает.

  21. Ann:

    Подскажите пожалуйста, что необходимо сделать чтобы по щелчку пользователя загружались одновременно 2 разных странички в разные div? Возможно ли это?

  22. Barzoy:

    >Подскажите пожалуйста, что необходимо сделать
    >чтобы по щелчку пользователя
    >загружались одновременно 2 разных
    >странички в разные div? Возможно ли это?

    1) Либо отправлять 2 запроса, один - для одной страницы, другой - для второй. Они независимо друг от друга отработают и подгрузят нужные данные.

    2) Либо отправлять один запрос, но в ответ на него выдавать текст страниц, разделив их каким-нибудь хитрым разделителем (например: !|-!-|!), и при получении текста на стороне клиента разбивать полученное содержимое по этому разделителю:

    /*Как-то так =) хз, так оно пишется или нет, давно c JS не работал =)*/

    var a = xmlHttp.responseText.split('!|-!-|!');
    div1.innerHTML=a[0];
    div2.innerHTML=a[1];

  23. igor:

    Подскажите пожалуйста, что необходимо сделать, для того чтобы получать з PHP файла ответ а не виводить в нем echo?

  24. Werevolff:

    верни переменную с ответом, Игорь...
    Буду пробовать, а то с этими электронными книгами одни проблемы: программа распознования текста на сканере видимо плохо работала и все скрипты перекаверкало, а я яваскрипт терпеть не могу. PHP незаметно полюбил, а в яваскрипт врубиться не могу... да и синтаксис сложно учить. Наприимер, я ни в одном справочнике по языку сценариев пока не видел описание работы xmlHTTPRequest объекта

  25. igor:

    Werevolff а не подскажеж как ответ вернуть?а то я не оч дружу з ajax'oм или посоветуй хорошою книгу =).
    icq:478617403

  26. Роман:

    Народ, а у меня вот какая проблема (код):

    Скрипт не изменен, но почему то http_request.status =0!!!!!!!!!!! И естессно ошибка ((( Что делать? Если не трудно киньте ответ на мыло....
    Заранее спасибо!

  27. fish:

    А можно где-то увидеть просто пример передачи аяксом скрипту какую нибудь переменную, скрипт обрабатывает переменную и аяксом вывести результат?

  28. Vincent:

    Спасибо. Наконец-то нормалек статья о этой чудо технологии

  29. Гость:

    Автору огромное уважение. Статья супер

  30. someone:

    Здравствуйте!
    Приведите пожалуйста пример как эта строка: "name=value&anothername=othervalue&so=on" должна в реальности выглядить, а то что-то никак не получается send с параметрами организовать корректный(

  31. Ljowuk:

    function sendRequest(url, params, httpMethod)
    {
    if(!httpMethod)
    {
    httpMethod = "POST";
    }

    req = initXMLHTTPRequest();

    if(req)
    {
    req.onreadystatechange = onReadyState;
    req.open(httpMethod, url, true);
    req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    req.send(params);
    }
    }

    name = document.getElementById("txtLogin").value;
    pass = document.getElementById("pswrdLogin").value;

    sendRequest("your url", "login=" + name + "&pass=" + pass);

  32. MysteryDragon:

    > Скрипт не изменен, но почему то http_request.status =0!!!!!!!!!!! И естессно ошибка ((( Что делать? Если не трудно киньте ответ на мыло....
    У меня тоже возникала проблема такого плана, я заметил, что она возникает в случае, если а) странички находятся на своем собственном компе (без разницы, запущен ли эмуль сервера); б) если странички находятся на разных серверах.

  33. Женя:

    Полезная, конечно, статеечка, но того что искал я в ней не нашёл.
    У меня возникла проблема с разбором объекта полученого от responseXML в IE.
    Все методы и свойства (getElementsByTagName, firstChild и т.д.) работают во всех браузерах кроме IE. В IE responseXML тоже возвращает объект , но совсем не такой, какой можно использовать для дальнейшего разбора обычными средствами.
    Один дядечка мне сказал, что возвращаемый DOMDocument в IE реализован не native, а в виде COM-объекта и пройти по его коллекции свойств в IE не получится.
    Ну и что же из всего этого следует???... Можно всётаки, или не можно в IE полноценно AJAX использовать, или только с responseText-ом работать?...

  34. Shok:

    Автору уважуха!!! Избавил от головной боли!! по поводу кодировки, если кто не догнал еще как правлиьно сделать - нужно добавть
    header("Content-type: text/plain; charset=windows-1251");

  35. lav0708:

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

  36. thecerber:

    ВОТ! Это именно то, что я искал!!! Спасибо ;)

  37. Саша:

    Спасибо

  38. Тестовая Страница:

    Полезная статейка. Пригодилось. В ИЭ действительно не пашет :( НО пока и так хорошо.

  39. кс:

    Ой как мило то... 2007 год на дворе был, а они писали:
    >>>Статья интересная, но.... А чем хуже javascript и iframe? Тоже можно реализовать изменение страницы без перезагрузки. Причем тока стандартными средствами. Не нужно заботиться о всяких заголовках и обеспечивать кросбраузерность

    как в детство вернулся... когда только только аякс появился

  40. volK:

    здравствуйте! Посоветуйте что-нибудь почитать, давно хочу заняться изучением JS ajax и тд, но не могу найти ничего путного в сети что вносило бы ясноть.

    ася 3аДИН4 два12 шес8шес

  41. Андрей:

    Здравствуйте Уважаемые коллеги. Большое человеческое спасибо автору статьи за подробное и ясное изложение материала. "Быстрый старт" с технологией Ajax обеспечен! Уже модифицировал код для запроса данных по параметрам, передаваемым череp Get на страницу test.php. На "первое время" можно так:

    Сделать запрос к каталогу 125, файл №123457

    Но это, конечно, не самый красивый способ. Но для проверки и отладки вполне в моем случае подошел. Таких блоков может быть несколько, и скипт таким образом, можно тестировать с разным набором параметров. В релизе наиболее корректно использовать send() , см. статью выше.

  42. Андрей:

    Люди, внимание, в посте выше строка "Сделать запрос к каталогу 125, файл №123457" - это span с кодом. Как тест спан не интерпретировался.

Оставить комментарий