Mozilla.com

С чего начать

 

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

Что такое AJAX?

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

Рассмотрим две основные возможности, которые дает вам технология:

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

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

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

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

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

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

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

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

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

httpRequest.onreadystatechange = nameOfTheFunction;

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

httpRequest.onreadystatechange = function(){
// код обработчика
};

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

httpRequest.open('GET', 'http://www.example.org/some.file', true);
httpRequest.send(null);
  • Первый параметр функции open() — метод запроса HTTP (GET, POST, HEAD или любой другой метод, поддерживаемый сервером, который вы хотите использовать). Указывайте методы заглавными буквами в соответствии с HTTP стандартом; иначе некоторые браузеры (такие как Firefox) могут не обработать запрос. Информация о допустимых HTTP запросах доступна по адресу спецификации W3C
  • Второй параметр — URL запрашиваемой страницы. Из соображений безопасности вы не можете запрашивать страницы сторонних доменов. Убедитесь, что вы используете одинаковое доменное имя на всех страницах, в противном случае вы получите ошибку 'доступ запрещен' при вызове функции open(). Типичной ошибкой является отправка запроса на domain.tld в то время, как вы находитесь на странице сайта www.domain.tld.
  • Третий параметр указывает, является ли запрос асинхронным. Если он TRUE, то выполнение JavaScript продолжится в то время, пока ответ от сервера еще не получен. В этом и заключается асинхронность технологии.

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

name=value&anothername=othervalue&so=on

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

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

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

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

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

httpRequest.onreadystatechange = nameOfTheFunction;

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

if (httpRequest.readyState == 4) {
	// everything is good, the response is received
} else {
	// still not ready
}

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

  • 0 (Неинициализирован)
  • 1 (Инициализирован)
  • 2 (Отправлен)
  • 3 (Загружается)
  • 4 (Загружен)

(Источник)

Далее нужно проверить статус HTTP-ответа. Полный список кодов ответа сервера можно посмотреть на сайте W3C. Нам интересен только код ответа 200 OK.

if (httpRequest.status == 200) {
	// perfect!
} else {
	// there was a problem with the request,
	// for example the response may be a 404 (Not Found)
	// or 500 (Internal Server Error) response codes
}

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

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

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

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

<script type="text/javascript" language="javascript">
function makeRequest(url) {
	var httpRequest;

	if (window.XMLHttpRequest) { // Mozilla, Safari, ...
		httpRequest = new XMLHttpRequest();
		if (httpRequest.overrideMimeType) {
			httpRequest.overrideMimeType('text/xml');
			// See note below about this line
		}
	} 
	else if (window.ActiveXObject) { // IE
		try {
			httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
		} 
		catch (e) {
			try {
				httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
			} 
			catch (e) {}
		}
	}

	if (!httpRequest) {
		alert('Giving up :( Cannot create an XMLHTTP instance');
		return false;
	}
	httpRequest.onreadystatechange = function() { alertContents(httpRequest); };
	httpRequest.open('GET', url, true);
	httpRequest.send('');

}

function alertContents(httpRequest) {
	if (httpRequest.readyState == 4) {
		if (httpRequest.status == 200) {
			alert(httpRequest.responseText);
		} else {
			alert('There was a problem with the request.');
		}
	}
}
</script>
<span style="cursor: pointer; text-decoration: underline" onclick="makeRequest('test.html')">Make a request</span>


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

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

Замечание: Строка httpRequest.overrideMimeType('text/xml'); вызовет ошибки в консоли JavaScript в Firefox 1.5 или более позднем, как задокументировано в баге 311724, если страница, полученная с помощью XMLHttpRequest не является правильным XML (например, если это обычный текст). На самом деле это корректное поведение.

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

Замечание 3: Если переменная httpRequest объявлена глобально, то в ситуации, когда запросы делаются сразу друг за другом, первый запрос будет «затёрт» вторым. Чтобы избежать такого эффекта состязаний, объявляйте переменную httpRequest локально в функции и передавайте ее в alertContent().

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

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

Таким образом, если вам необходимо передать httpRequest функции-обработчику, вы должны сделать это косвенно через анонимную функцию или использовать httpRequest как глобальную переменную. Вот пример:

httpRequest.onreadystatechange = function() { alertContents(httpRequest); }; //1 (для конкурирующих запросов)
httpRequest.onreadystatechange = alertContents; //2 (глобальное определение)

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


Замечание 5: В случае ошибки (например, если сервер упал), при попытке доступа к переменной .status будет сгенерировано исключение в методе onreadystatechange. Убедитесь, что if...then заключено в try...catch. См. (баг 238559).

function alertContents(httpRequest) {
	try {
		if (httpRequest.readyState == 4) {
			if (httpRequest.status == 200) {
				alert(httpRequest.responseText);
			} else {
				alert('There was a problem with the request.');
			}
		}
	}
	catch( e ) {
		alert('Caught Exception: ' + e.description);
	}
}

Шаг 4 — Работа с XML ответом

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

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

<?xml version="1.0" ?>
<root>
	I'm a test.
</root>

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

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

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

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

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

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