AJAX, Ajax (ˈeɪdʒæks, от англ. Asynchronous Javascript and XML — «асинхронный JavaScript и XML») — подход к построению интерактивных пользовательских интерфейсов веб-приложений, заключающийся в «фоновом» обмене данными браузера с веб-сервером. Т.е. ajax — это не не конкретные инструменты, это методика получения данных.
Получение только части данных, а не обновление всей страницы, работает быстрее и улучшает пользовательский опыт. AJAX может использоваться при необходимости реализации таких структур как infinity scroll, live search, lazyload и т.д.
Данные в AJAX транспортируются чаще всего в одном из следующих форматов:
Техника получения только части данных в JavaScript может быть реализована с помощью объекта XMLHttpRequest и с помощью скрытого фрейма.
Простейший пример использования XMLHttpRequest выглядит так:
var request = new XMLHttpRequest();
request.open('GET', '/data.php');
request.send();
request.onreadystatechange = function() {
if (request.readyState == 4) {
if (request.status != 200) {
console.error( request.status + ': ' + request.statusText );
} else {
console.log(request.responseText);
}
}
};
У созданного XMLHttpRequest есть следующие методы:
В процессе выполнения запроса и по его завершению заполняются свойства экземпляра XMLHttpRequest:
Список самых популярных кодов ответа сервера:
Экземпляр XMLHttpRequest генерирует следующие события:
Коды состояния AJAX-запроса:
Если есть необходимость установить таймаут ожидания запроса, то для этого задают свойству timeout значение в миллисекундах:
request.timeout = 5000;
Иногда при работе с запросом необходимо отправить HTTP-заголовки или прочитать заголовки ответа сервера. Для этих целей используются следующие методы:
Заголовки можно добавить после конфигурирования запроса, но до его отправки.
На работу с заголовками для XMLHttpRequest наложены ограничения, связанные с безопасностью. Так, нельзя при отправке запроса принудительно указать заголовки Referer, Host, Content-Length и некоторые другие. Такие заголовки браузер формирует сам и не дает для них доступа для Javascript.
Из getResponseHeader и getAllResponseHeaders нельзя прочитать заголовки Set-Cookie и Set-Cookie2.
Кроме "классических" заголовков, подобных тем, которые передаются при отравке обычной формы, можно передать специальный заголовок X-Requested-With со значением XMLHttpRequest для указания серверу, что запрос выполняется с помощью AJAX.
Повторная установка заголовка не перезаписывает, а дополняет его.
IE версий 8 и 9 также поддерживают AJAX-запросы, но возможности по использованию XMLHttpRequest там ограничены. Например, из событий доступно только onreadystatechange. Поэтому для этих версий используют объекты XDomainRequest. Для IE 10 и выше XMLHttpRequest работает полноценно и можно использовать его. Кроссбраузерный код создания запроса может иметь следующий вид:
var request = new XMLHttpRequest();
if(!('onload' in request)) {
request = new XDomainRequest();
}
AJAX-запросы, как и обычные страницы, могут кешироваться браузером. IE9 и ниже кеширует все запросы по умолчанию. Чтобы предотвратить кеширование можно:
При отправке GET-запросов при необходимости передать параметры модифицируют URL, на который нужно отправить запрос. В случает с POST-запросами все необходимые передаваемые на сервер данные помещаются в тело запроса. При отправке обычной формы формирование тела запроса осуществляет браузер, а при отправке AJAX-запроса тело должен сформировать скрипт. При этом данные передаются в одной из кодировок, представленных ниже.
При необходимости передачи, например, кириллистических строк в параметрах GET-запроса в AJAX необходимо вручную закодировать эти строки с помощью urlencoded:
var input = "Инпут";
var url = '/data.php?name=' + encodeURIComponent( input );
При этом все символы, кроме символов латиницы, цифр и знаков базовой пунктуации заменяются на последовательности unicode.
Запросы POST также можно отправлять в кодировке urlencoded. Особенностью POST-запросов является необходимость явного указания кодировки в заголвоке запроса. В случае кодировки urlencoded в заголовок передают значение application/x-www-form-urlencoded. Код такого запроса будет выглядеть как:
var input = "Инпут";
var url = /data.php';
var request = new XMLHttpRequest();
var body = 'input=' + encodeURIComponent(input);
request.open('POST', url);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.send(body);
Для данной кодировки всегда используется UTF-8.
При использовании кодировки urlencoded объем данных при кодировании может сильно увеличиваться, а для больших файлов перекодирование могло бы просходить долго и нагружать браузер. Потому для передачи файлов была создана кодировка multipart/form-data. Но исползовать ее можно не только для передачи файлов, но и для обычныx POST-запросов.
В multipart/form-data передаваемые поля идут в теле запроса друг за другом в исходном виде и разделяются специально сгенерированными разделителями boundary, гарантирующим, что данные не будут смешаны со служебной информацией.
Для отправки POST-запроса в multipart/form-data с помощью AJAX можно воспользоваться следующим кодом:
var input = "Инпут";
var url = /data.php';
var request = new XMLHttpRequest();
var boundary = Math.random().toString().slice(2);
var body = '--' + boundary + '\r\n' +
'Content-Disposition: form-data; name="input"\r\n\r\n' +
input +
'\r\n' +
'--' + boundary + '--\r\n';
request.open('POST', url);
request.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
request.send(body);
Севременные браузеры поддерживают формат кодирования форм FormData. Форму можно отправить так:
var myForm = new FormData();
myForm.append("input", "Инпут");
var request = new XMLHttpRequest();
request.open("POST", url);
request.send(myForm);
В конструкторе есть необязательный параметр, в который можно передать DOM-элемент существующей формы. С помощью append можно добавлять новые поля. Такая форма при отправке будет использовать кодировку multipart/form-data.
Данные для AJAX-запроса можно передавать и как text/plain, и как application/json.
var input = {input: "Инпут"};
var url = /data.php';
var request = new XMLHttpRequest();
var json = JSON.stringify(input);
request.open('POST', url);
request.setRequestHeader('Content-type', 'application/json; charset=utf-8');
request.send(json);
По умолчанию AJAX-запросы доступны только для документов, у которых совпадает протокол, домен и порт с текущим документом. Однако технически есть возможность отправить запрос на другой домен. Такие запросы называются кроссдоменными. Со стороны JavaScript такой запрос может ничем не отличаться от обычного. Единственное ограничение - такой запрос не может быть синхронным. В остальном за доступность кроссдоменного запроса в большей степени отвечает браузер.
За возможность осуществления кроссдоменных запросов отвечает политика CORS (Cross-Origin Resource Sharing). Все запросы в ней разделяются на простые и не простые. К простым относят запросы, которые имеют простой метод - GET, POST или HEAD - и простые заголовки: Accept, Accept-Language, Content-Language и Content-Type со значениями application/x-www-form-urlencoded, multipart/form-data или text/plain. Все остальные запросы считаются "не простыми".
Простые запросы можно сформировать с помощью формы, а для отправки "непростого" нужно использовать AJAX.
Для выполнения простого вопроса через AJAX достаточно совпадения Access-Control-Allow-Origin в заголовке ответа совпадающим с Origin страницы, выполняющей запрос. Если необходимо разрешить все кроссдоменные запросы, то достаточно указать Access-Control-Allow-Origin: * в заголовках сервера.
Для чтения заголовков сервера, отличных от "простых" (Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma) они должны быть указаны в заголовке ответа Access-Control-Expose-Headers.
Для передачи вместе с запросом еще и данных о cookie пользователя устанавливают свойство withCredentials в true. Чтобы такие данные передались сервер должен отправить заголовок Access-Control-Allow-Credentials: true.
"Непростые" запросы инициализируют дополнительный подзапрос, которые спрашивает у сервера, разрешены ли "непростые" методы или заголовки. Такой запрос отправляется методом OPTIONS, не содержит тела и содержит заголовки Access-Control-Request-Method и Access-Control-Request-Headers. В ответ сервер в заголовках Access-Control-Allow-Method и Access-Control-Allow-Headers перечень допустимых методов и заголовков или ошибку. Дополнительно сервер может в заголовке Access-Control-Max-Age передать время в секугдах, на которое нужно закешировать разрешение.
Запрос XMLHttpRequest состоит из стадии закачки данных на сервер и стадии получения ответа. Ответ сервера меняет соответствующие свойства у экземпляра XMLHttpRequest, а информация о закачке попадает в свойство upload.
Для свойства upload существуют следующие события:
Для стадий закачки и скачивания в событии onprogress для события доступна информация о переданном числе байт (event.loaded) и общем числе байт (event.total). Если информация об общем числе байт недоступна, то в свойстве event.lengthComputable будет false. При закачке на сервер lengthComputable всегда true, т.к. браузер всегда знает размер передаваемых данных.
Событие onprogress происходит при передаче каждого байта, но не чаще раза в 50мс. Обновленный responseText всегда доступен при каждом обновлении прогресса. Request.upload.onprogress указывает на то, что данные были переданы на сервер, но не гарантирует, что данные были получены и обработаны.
WebSocket - простой протокол безопасной кроссдоменной передачи данных между браузером и сервером. Сервер должен поддерживать технологию, чтобы браузер мог "общаться" с ним по этому протоколу.
var socket = new WebSocket('ws://example.com');
Созданный вебсокет имеет следующие события:
Данные по данному протоколу отправляются с помощью socket.send()