Выбрать главу

В следующей главе мы вернёмся к формам и поговорим про то, как мы можем делать их при помощи JavaScript.

XMLHttpRequest

Интерфейс, через который JavaScript в браузере может делать HTTP-запросы, называется XMLHttpRequest (заметьте, как прыгает размер букв). Он был разработан в Microsoft для браузера Internet Explorer в конце 1990-х. В это время формат XML был очень популярным в мире бизнес-программ – а в этом мире Microsoft всегда чувствовал себя, как дома. Он был настолько популярным, что аббревиатура XML была пришпилена перед названием интерфейса для работы с HTTP, хотя последний с XML вообще не связан.

И всё же имя не полностью бессмысленное. Интерфейс позволяет разбирать вам ответы, как если бы это были документы XML. Смешивать две разные вещи (запрос и разбор ответа) в одну – это, конечно, отвратительный дизайн, но что поделаешь.

Когда интерфейс XMLHttpRequest был добавлен в Internet Explorer, стало можно делать вещи, которые раньше было делать очень сложно. К примеру, сайты стали показывать списки из подсказок, пока пользователь вводит что-либо в текстовое поле. Скрипт отправляет текст на сервер через HTTP одновременно с набором текста пользователем. Сервер, у которого есть база данных для возможных вариантов ввода, ищет среди записей подходящие и возвращает их назад для показа. Это выглядело очень круто – люди до этого привыкли ждать перезагрузки всей страницы после каждого взаимодействия с сайтом.

Другой важный браузер того времени Mozilla (позже Firefox), не хотел отставать. Чтобы разрешить делать сходные вещи, Mozilla скопировал интерфейс вместе с названием. Следующее поколение браузеров последовало этому примеру, и сегодня XMLHttpRequest является стандартом de facto.

Отправка запроса

Чтобы отправить простой запрос, мы создаём объект запроса с конструктором XMLHttpRequest и вызываем методы open и send.

var req = new XMLHttpRequest();

req.open("GET", "example/data.txt", false);

req.send(null);

console.log(req.responseText);

// → This is the content of data.txt

Метод open настраивает запрос. В нашем случае мы решили сделать GET запрос на файл example/data.txt. URL, не начинающиеся с названия протокола (например, http:) называются относительными, то есть они интерпретируются относительно текущего документа. Когда они начинаются со слэша (/), они заменяют текущий путь – часть после названия сервера. В ином случае часть текущего пути вплоть до последнего слэша помещается перед относительным URL.

После открытия запроса мы можем отправить его методом send. Аргументом служит тело запроса. Для запросов GET используется null. Если третий аргумент для open был false, то send вернётся только после того, как был получен ответ на наш запрос. Для получения тела ответа мы можем прочесть свойство responseText объекта request.

Можно получить из объекта response и другую информацию. Код статуса доступен в свойстве status, а текст статуса – в statusText. Заголовки можно прочесть из getResponseHeader.

var req = new XMLHttpRequest();

req.open("GET", "example/data.txt", false);

req.send(null);

console.log(req.status, req.statusText);

// → 200 OK

console.log(req.getResponseHeader("content-type"));

// → text/plain

Названия заголовков не чувствительны к регистру. Они обычно пишутся с заглавной буквы в начале каждого слова, например “Content-Type”, но “content-type” или “cOnTeNt-TyPe” будут описывать один и тот же заголовок.

Браузер сам добавит некоторые заголовки, такие, как “Host” и другие, которые нужны серверу, чтобы вычислить размер тела. Но вы можете добавлять свои собственные заголовки методом setRequestHeader. Это нужно для особых случаев и требует содействия сервера, к которому вы обращаетесь – он волен игнорировать заголовки, которые он не умеет обрабатывать.

Асинхронные запросы

В примере запрос был окончен, когда заканчивается вызов send. Это удобно потому, что свойства вроде responseText становятся доступными сразу. Но это значит, что программа наша будет ожидать, пока браузер и сервер общаются меж собой. При плохой связи, слабом сервере или большом файле это может занять длительное время. Это плохо ещё и потому, что никакие обработчики событий не сработают, пока программа находится в режиме ожидания – документ перестанет реагировать на действия пользователя.

Если третьим аргументом open мы передадим true, запрос будет асинхронным. Это значит, что при вызове send запрос ставится в очередь на отправку. Программа продолжает работать, а браузер позаботиться об отправке и получении данных в фоне.