AJAX-запросы и XMLHttpRequest

Объект XMLHttpRequest

Последнее обновление: 04.11.2023

Код javascript может взаимодействовать с каким-нибудь ресурсом в сети интернет, например, с каким-нибудь веб-сайтом или веб-сервисом, грубо говоря с сервером. Для взаимодействия кода javascript с сервером обычно применяется такая технология как Ajax. Ajax представляет технологию для отправки запросов к серверу из клиентского кода JavaScript без перезагрузки страницы. Сам термин расшифровывается как Asynchronous JavaScript And XML. То есть изначально AJAX предполагал асинхронное взаимодействие клиента и сервера посредством данных в формате XML. Хотя сейчас XML во многом вытеснил формат JSON.

Одним из способов для отправки ajax-запросов является применение объекта XMLHttpRequest. Данный объект создается с помощью одноименной функции-конструктора:

const xhr = new XMLHttpRequest();

Для настройки и отправки ajax-запросов объект XMLHttpRequest предоставляет ряд методов:

  • abort(): прерывает запрос

  • getAllResponseHeaders(): возвращает все заголовки HTTP-ответа в виде строки

  • getResponseHeader(header): возвращает значение заголовка header.

  • open(method, url[, async[, user[, password]]]): инициализирует ajax-запрос.

    Эта функция принимает пять параметров, из которых первые два являются обязательными:

    • method: тип запроса ("GET", "POST", "PUT", "DELETE" и т.д.)

    • url: адрес ресурса, к которому отправляется запрос

    • async: логическое значение, которое указывает, будет ли запрос асинхронным. Если значение true (значение по умолчанию), то запрос асинхронный

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

    • user: имя пользователя, которое применяется при его аутентификации на сервере (то есть для определения, какой именно пользователь осуществил запрос), по умолчанию равно null

    • password: пароль пользователя, который применяется при его аутентификации на сервере, по умолчанию равно null

  • overrideMimeType(mime): переопределяет MIME-тип, возвращаемый сервером

  • send(data): отправляет запрос. С помощью необязательного параметра data можно передать данные, которые отправляются на сервер. Если этому параметру не передано никакого значения, то его значение по умолчанию null.

  • setRequestHeader(header, value): устанавливает значение value для заголовка header, который будет отправляться в запросе

Свойства XMLHttpRequest

В дополнение к методам объект XMLHttpRequest предоставляет ряд свойств, которые позволяют настроить отправку запроса или извлечт полученные от сервера данные:

  • response: возвращает ответ сервера. Ответ может представлять объекты ArrayBuffer, Blob, Document, объект JSON, строку или null (если запрос еще не завершен или завершился неудачно)

  • responseType: возвращает тип ответа. Есть следующие типы:

    • "": пустая строка

    • "arraybuffer": ответ представляет объект ArrayBuffer, которые содержит бинарные данные

    • "blob": ответ представляет объект Blob, которые содержит бинарные данные

    • "document": ответ представляет объект Document (документ HTML/XML)

    • "json": ответ представляет данные в формате json

    • "text": ответ представляет текст

  • responseText: возвращает ответа сервера в виде строки или значения null (если запрос еще не завершен или завершился неудачно)

  • responseXML: возвращает объект Document (документ HTML/XML), если ответ от сервера в формате XML/HTML

  • readyState: хранит состояния запроса, которое представляет число:

    • 0: объект XMLHttpRequest создан, но метод open() еще не был вызван для инициализации объекта

    • 1: метод open() был вызван, но запрос еще не был отправлен методом send()

    • 2: запрос был отправлен, заголовки и статус ответа получены и готовы к использованию

    • 3: ответ получен от сервера

    • 4: выполнение запроса полностью завершено (даже если получен код ошибки, например, 404)

    Соответственно проверив данное свойство, мы можем понять, на какой стадии находится запрос

  • status: содержит статусный код ответа HTTP, который пришел от сервера. С помощью статусного кода можно судить об успешности запроса или об ошибках, которые могли бы возникнуть при его выполнении. Например, статусный код 200 указывает на то, что запрос прошел успешно. Код 403 говорит о необходимости авторизации для выполнения запроса, а код 404 сообщает, что ресурс не найден и так далее.

  • statusText: возвращает текст статуса ответа, например, "200 OK"

  • timeout: устанавливает тайм-аут - время в миллисекундах, во время которого может выполняться запрос. Если это время истекло, а запрос еще не завершен, то запрос прерывается

  • withCredentials: определить, следует ли включать в запрос учетные данные, например, файлы cookie

События и обработчики событий XMLHttpRequest

Для отслеживания состояния запроса можно применять события XMLHttpRequest:

  • abort: срабатывает после прерывания запроса. Для установки обработчика применяется свойство onabort

  • progress: срабатывает при выполнения запроса. Для установки обработчика применяется свойство onprogress

  • load: срабатывает после выполнения запроса. Для установки обработчика применяется свойство onload

  • loadend: срабатывает после успешного выполнения запроса. Для установки обработчика применяется свойство onloadend

  • error: срабатывает при возникновении ошибки. Для установки обработчика применяется свойство onerror

  • loadstart: срабатывает после запуска запроса. Для установки обработчика применяется свойство onloadstart

  • timeout: срабатывает, если запрос прерывается из-за тайм-аута. Для установки обработчика применяется свойство onimeout

  • readystatechange: возникает каждый раз, когда изменяется значение свойства readyState. Для установки обработчика применяется свойство onreadystatechange

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

  • onabort: вызывается, когда запрос был прерван с помощью метода abort().

  • onerror: вызывается при возникновении ошибки.

  • onload: вызывается, когда запрос успешно выполнен и доступен ответ.

  • onloadend: вызывается после успешного выполнения запроса.

  • onloadstart: вызывается после запуска запроса.

  • onprogress: вызывается при выполнении запроса.

  • onreadystatechange: вызывается при изменении состояния запроса.

  • ontimeout: вызывается, если запрос прерывается из-за тайм-аута.

  • upload: можно использовать для отслеживания статуса при загрузке данных.

Процесс выполнения ajax-запроса

В общем случае процесс выполнения ajax-запроса с помощью XMLHttpRequest выглядит следующим образом:

  1. Создается объект XMLHttpRequest

    const request = new XMLHttpRequest();
  2. Устанавливается обработчик событий загрузки (например, через свойство onload), который будет вызываться после завершения HTTP-запроса

    request.onload = (event) => { console.log("request finished");}
  3. Запускается HTTP-запрос с помощью метода open(). Методу передается метод HTTP, который будет использоваться для запроса (например, GET или POST), URL-адрес, к которому должен быть отправлен запрос, и при необходимости другие необязательные аргументы

    request.open("GET", "http://localhost/hello");
  4. При необходимости производиться дополнительная конфигурация HTTP-запроса. Например, с помощью метода setRequestHeader() можно определить заголовки, которые будут отправляться вместе с запросом. Однако важно выполнить эту настройку после предыдущего шага, то есть после вызова метода open(), но перед следующим шагом, то есть перед вызовом метода send()

    request.setRequestHeader("Accept", "text/plain"); // установка заголовка на прием данных

  5. Непосредственно отправляется HTTP-запрос с помощью вызова метода send(). При желании в этот метод можно передать данные для отправки на сервер

    request.send()
    1. Вначале рассмотрим простейший пример, как выполнять запрос к серверу с помощью XMLHttpRequest

      Определение ресурса на севере

      Поскольку Ajax предполагает взаимодействие клиента и сервера, то для работы с Ajax нам потребуется некоторый сетевой ресурс, к которому мы будем обращаться. Для эмуляции сетевого ресурса используем локальный веб-сервер. Веб-сервер может быть любым. В данном случае воспользуемся самым простым вариантом - Node.js, так как эта технология двольно проста, доступна для всех основных операционных систем и также также позволяет использовать javascript для создания приложений. Но естественно перед созданием приложения необходимо установить Node.js. В данном случае не потребуется никаких знаний node.js, весь используемый код подробно описывается. Но опять же вместо node.js это может быть любая другая технология сервера - php, asp.net, python и т.д. либо какой-то определенный веб-сервер типа Apache или IIS.

      Итак, создадим на жестком диске папку для файлов веб-сервера. Например, в моем случае это папка C:\app. Далее в этой папке определим файл сервера. Пусть он будет называться server.js и будет иметь следующий код:

      const http = require("http");
      const fs = require("fs");
         
      http.createServer(function(request, response){
           
      	if(request.url == "/hello"){
              response.end("Hello METANIT.COM");
          }
          else{
      		fs.readFile("index.html", (error, data) => response.end(data));
          }
      }).listen(3000, ()=>console.log("Сервер запущен по адресу http://localhost:3000"));
      

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

      const http = require("http");	// для обработки входящих запросов
      const fs = require("fs");		// для чтения с жесткого диска файла index.html
      

      Для создания сервера применяется функция http.createServer(). В эту функцию передается функция-обработчик, которая вызывается каждый раз, когда к серверу приходит запрос. Эта функция имеет два параметра: request (содержит данные запроса) и response (управляет отправкой ответа).

      В функции-обработчике с помощью свойства request.url мы можем узнать, к какому ресурсу на сервере пришел запрос. Так, в данном случае, если пришел запрос по пути "/hello" (условно к ресурсу "/hello"), то оправляем в ответ с помощью метода response.end() текст "XMLHttpRequest на METANIT.COM":

      if(request.url == "/hello"){
      	response.end("Hello METANIT.COM");
      }
      

      Если запрос пришел к какому-то другому ресурсу, то отправляем файл index.html, который мы дальше определим:

      else{
      	fs.readFile("index.html", (error, data) => response.end(data));
      }
      

      Для считывания файлов применяется встроенная функция fs.readFile(). Первый параметр функции - адрес файла (в данном случае предполагается, что файл index.html находится в одной папке с файлом сервера server.js). Второй параметр - функция, которая вызывается после считывания файла и получет его содержимое через свой второй параметр data. Затем считанное содежимое также может быть отпавлено с помощью функции response.end(data).

      В конце с помощью функции listen() запускаем веб-сервер на 3000 порту. То есть сервер будет запускаться по адресу http://localhost:3000/

      Выполнение ajax-запроса

      Теперь в папке сервера определим простенький файл index.html

      веб-сервер node.js для тестирования XMLHttpRequest в javascript

      Определим в этом файле следующее содежимое:

      <!DOCTYPE html>
      <html>
      <head>
          <meta charset="utf-8" />
          <title>METANIT.COM</title>
      </head>
      <body>
      <script>
      const xhr = new XMLHttpRequest();
      // GET-запрос к ресурсу /hello
      xhr.open("GET", "/hello");
      
      // обработчик получения ответа сервера
      xhr.onload = () => {
          if (xhr.status == 200) {                // если код ответа 200
              console.log(xhr.responseText);      // выводим полученный ответ на консоль браузера
          } else {                                // иначе выводим текст статуса
              console.log("Server response: ", xhr.statusText);
          }
      };
      xhr.send();     // выполняем запрос
      </script>
      </body>
      </html>
      

      Здесь в метод xhr.open() в качестве типа запроса передается тип "GET", а в качестве адреса ресурса - "/hello".

      xhr.open("GET", "/hello");

      Для отслеживания завершения запроса устанавливаем обработчик для события load с помощью свойства xhr.onload:

      xhr.onload = () => {
          if (xhr.status == 200) {                // если код ответа 200
              console.log(xhr.responseText);      // выводим полученный ответ на консоль браузера
          } else {                                // иначе выводим текст статуса
              console.log("Server response: ", xhr.statusText);
          }
      };
      

      В данном случае в качестве обработчика события выступает лямбда-выражение. И когда запрос завершится, сработает данный обработчик. Если запрос был успешно обрабатан, то по умолчанию сервер посылает статусный код 200. Как мы помним из кода сервера, при обращении по адресу "/hello" сервер посылает клиенту строку. И чтобы получить данную строку, обращаемся к свойству xhr.responseText. Если же в процессе обращения к серверу возникла какая-то ошибка или статусный код не 200, то с помощью свойства xhr.statusText выводит текст статуса ответа.

      И в конце собственно выполняем запрос:

      xhr.send();     // выполняем запрос

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

      Теперь в консоли перейдем к папке сервера с помощью команды cd и запустим сервер с помощью команды node server.js

      C:\app>node server.js
      Сервер запущен по адресу http://localhost:3000
      
      

      После запуска сервера мы можем перейти в браузере по адресу http://localhost:3000, нам отобразится страница, в javascript-коде которой произойдет обращение к ресурсу "/hello":

      XMLHttpRequest в javascript

      В итоге при обращении к ресурсу "/hello" сервер отправит отправит строку "XMLHttpRequest на METANIT.COM", которую мы сможем получить на веб-странице.

      В примере выше применялся относительный путь, но также можно было бы использовать абсолютный путь с указанием протокола, адреса сервера и порта:

      xhr.open("GET", "http://localhost:3000/hello");
      

      Вместо события load мы также могли бы обрабатывать событие readystatechange объекта XMLHttpRequest, которое возникает каждый раз, когда изменяется значение свойства readyState:

      <!DOCTYPE html>
      <html>
      <head>
          <meta charset="utf-8" />
          <title>METANIT.COM</title>
      </head>
      <body>
      <script>
      const xhr = new XMLHttpRequest();
      // GET-запрос к ресурсу /hello
      xhr.open("GET", "/hello");
      
      // обработчик получения ответа сервера
      xhr.onreadystatechange = () => {
          if (xhr.readyState == 4) {                  // если запрос завершен
              if (xhr.status == 200) {                // если код ответа 200
                  console.log(xhr.responseText);      // выводим полученный ответ на консоль браузера
              } else {                                // иначе выводим текст статуса
                  console.log("Server response: ", xhr.statusText);
              }
          }
      };
      xhr.send();     // выполняем запрос
      </script>
      </body>
      </html>
      

      Здесь в обработчике события сначала проверяет состояние запроса - если код состояния равен 4, то обрабатывает ответ от сервера. Остальная логика та же, что и предыдущем случае.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850