Что такое AJAX? Создание асинхронных запросов
В этом уроке разберём создание простых асинхронных AJAX запросов к серверу. На примерах рассмотрим как их выполнить с помощью методов GET и POST. Обработку запросов на стороне сервера выполним с помощью PHP.
Что такое AJAX?
AJAX – это аббревиатура от «Asynchronous JavaScript and XML», которая дословно переводится как «асинхронный JavaScript и XML».
Что означают эти слова?
- асинхронный – действие выполняется в фоне (не в основном потоке), другими словами, таким образом, что оно не мешает пользователю взаимодействовать со страницей;
- JavaScript – язык, на котором всё это делается (т.е. создание и настройка запроса, отправка его на сервер, получение ответа и его разбор, обновление страницы);
- XML – формат для хранения и передачи данных, в настоящее время вместо него чаще используется JSON, но кроме них можно использовать и другие форматы.
Что такое AJAX? AJAX – это термин, который описывает как можно используя существующие технологии получать данные с сервера в фоновом режиме и использовать их для обновления страницы (без перезагрузки). Основная цель AJAX – это сделать сайты и веб-приложения более удобными, быстрыми и отзывчивыми.
Основные преимущества использования AJAX:
- снижение трафика (из-за уменьшения объёма передаваемых данных между клиентом и сервером);
- уменьшение нагрузки на сервер (не нужно генерировать всю страницу, а только ту часть, которую нужно обновить);
- увеличение быстродействия и отзывчивости (нет необходимости в полной перезагрузки страницы, достаточно обновить содержимое только отдельных блоков);
- повышение интерактивности (с помощью AJAX можно сразу отображать результаты и сделать ресурс более удобным для пользования).
Взаимодействие с сервером через асинхронные запросы осуществляется посредством XHR
или метода fetch()
.
Создание асинхронных запросов с помощью XHR
Что такое асинхронный запрос, мы уже разобрали выше. Т.е. это такой, который выполняется в фоне и не мешает пользователю взаимодействовать со страницей. А это значит, что при отправке такого запроса, страница не «замораживается», с ней можно продолжать взаимодействовать.
XHR
– это аббревиатура от объекта XMLHttpRequest
, который как раз и позволяет взаимодействовать с сервером через AJAX.
Написание запроса можно разбить на следующие этапы.
Этап 1. Создание экземпляра объекта XMLHttpRequest
:
const xhr = new XMLHttpRequest();
Этап 2. Инициализация запроса с помощью метода open()
:
xhr.open(method, url[, async[, user[, password]]]);
Где:
method
– метод отправки запроса на сервер (GET
,POST
,PUT
,PATCH
,DELETE
);url
– URL для отправки запроса;async
– определяет, как следует выполнять запрос: асинхронно (true
– по умолчанию) или нет (false
);user
иpassword
– имя пользователя и пароль, использующиеся для аутентификации (по умолчанию имеют значениеnull
).
Например:
// GET – метод, по которому будем делать запрос
// requestURL – переменная, содержащая URL для отправки запроса
xhr.open('GET', requestURL);
Этап 3. Назначение обработчика на событие readystatechange
объекта xhr
:
xhr.onreadystatechange = function() {
// ...
}
Это событие происходит при изменении статуса запроса readyState
.
readyState
– это свойство, содержащее числовой код, по которому можно определить в какой стадии сейчас находится запрос.
Статусы кодов readyState
:
- 0 – создан объект
XMLHttpRequest
, но методopen()
ещё не вызывался; - 1 – открыто новое соединение с помощью
open()
(этот этап также включает установку значений HTTP заголовкам с помощьюsetRequestHeader()
); - 2 – отправлен (вызван
send()
и получены заголовки ответа); - 3 – получена часть ответа;
- 4 – завершён.
Из всех этих статусов нам интересен только 4. Он будет означать, что ответ от сервера получен и его можно обработать. Остальные коды на практике практически не используются.
Таким образом напишем проверку на равенство значения readyState
числу 4:
xhr.onreadystatechange = function() {
if (xhr.readyState !== 4) {
return;
}
// все в порядке, ответ получен
}
Следующее, что нужно проверить – это статус HTTP-ответа. Он находится в свойстве status
.
Если запрос был успешно выполнен сервером, то его статус будет 200. Другие ответы нам в большинстве случаев не интересны. Например, если status
равен 404 (запрашиваемый URL не найден), то в этом случае запрашиваемых данных нет и мы можем только как-то обработать эту ошибку.
Кроме кода статуса, нам доступен ещё его текстовый вариант. Получить его можно с помощью statusText
.
Добавим ещё одно условие в код: проверку status
на равенство 200.
xhr.onreadystatechange = function() {
// xhr.statusText – текстовый вариант статуса
if (xhr.readyState !== 4 || xhr.status !== 200) {
return;
}
// все в порядке, ответ получен и его статус равен 200
}
Теперь, если всё в порядке, мы можем получить данные и делать с ними всё, то угодно.
Получить данные (ответ от сервера) можно осуществляется с помощью xhr.response
:
Например, выведем полученный ответ от севера в консоль:
xhr.onreadystatechange = function() {
if (xhr.readyState !== 4 || xhr.status !== 200) {
return;
}
const response = xhr.response;
console.log(response);
}
Кроме этого, также имеются ещё xhr.responseText
и xhr.responseXML
. Они предназначены для получения ответа соответственно в виде строки и объекта XML Document. Они существовали в API раньше и остались по историческим причинам, хотя сейчас в них нет особой необходимости. Т.к. получить ответ можно с помощью xhr.response
, а желаемый его тип установить посредством xhr.responseType
.
Этап 4. Отправка запроса. Выполняется это с помощью метода send()
.
Если запрос асинхронный, то выполнение send()
не останавливает дальнейшее выполнение программы. В противном случае (если запрос синхронный), программа приостанавливается и возобновляет своё выполнение только после получения ответа от сервера.
В send()
при необходимости можно передать аргумент (данные серверу в теле запроса). Если это не сделать, то по умолчанию будет использоваться значение null
.
Запросы GET создаются без тела, все параметры, которые нужно передать серверу здесь указывается в самом URL. Поэтому чтобы тело запроса было пустое, как уже было отмечено выше, нужно вызвать метод send()
без аргументов или с аргументом null
.
Отправим запрос:
xhr.send();
Итоговый код:
const xhr = new XMLHttpRequest();
xhr.open('GET', requestURL);
xhr.onreadystatechange = function() {
if (xhr.readyState !== 4 || xhr.status !== 200) {
return;
}
const response = xhr.response;
console.log(response);
}
xhr.send();
Более современный способ – это вместо readystatechange
слушать события load
и error
:
const xhr = new XMLHttpRequest();
xhr.open('GET', requestURL);
// после получения какого-либо ответа от сервера
xhr.onload = () => {
if (xhr.status !== 200) {
// выводим ошибку в консоль
console.log(`Ошибка ${xhr.status}: ${xhr.statusText}`);
return;
}
// получаем ответ сервера
const response = xhr.response;
console.log(response);
};
// срабатывает, когда запрос не может быть выполнен (например, нет соединения или не корректный URL)
xhr.onerror = () => { // происходит, только когда запрос совсем не получилось выполнить
console.log(`Ошибка при выполнении запроса`);
};
xhr.send();
Для индикации прогресса загрузки предназначено событие progress
:
const xhr = new XMLHttpRequest();
xhr.open('GET', requestURL);
xhr.onload = () => { ... }
// вызывается по мере поступления данных
xhr.onprogress = (e) => {
// если сервер присылает заголовок Content-Length
if (e.lengthComputable) {
// e.loaded - количество загруженных байт
// e.total - количество байт всего
console.log(`Получено ${e.loaded} из ${e.total} байт`);
} else {
console.log(`Получено ${e.loaded} байт`);
}
};
xhr.onerror = () => { ... };
xhr.send();
Пример AJAX запроса для получения текстовых данных с сервера
В качестве примера напишем асинхронный AJAX запрос на чистом JavaScript, который будет загружать «/examples/ajax/01.html» с сервера в #result
:

<button type="button" id="get">Получить текст с сервера</button>
<div id="result"></div>
<script>
function getData() {
// URL на который будем отправлять GET запрос
const requestURL = '/examples/ajax/01.html';
const xhr = new XMLHttpRequest();
xhr.open('GET', requestURL);
xhr.onload = () => {
if (xhr.status !== 200) {
return;
}
document.querySelector('#result').innerHTML = xhr.response;
}
xhr.send();
}
// при нажатию на кнопку
document.querySelector('#get').addEventListener('click', () => {
getData();
});
</script>
Содержимое «01.html»:
<p>Добро пожаловать на сайт <a href="https://itchief.ru/">itchief.ru</a>!</p>
Пример AJAX GET запроса с параметром
В этом примере напишем асинхронный AJAX запрос, который будет при нажатии на кнопку загружать полученные данные в качестве элементов списка.
1. Для генерации данных на сервере создадим простой php-файл, который будет возвращать массив из определённого количества элементов в формате JSON.
<?php
$nums = (int) $_GET['nums'];
$arr = ['Audi', 'BMW', 'Ford', 'Hyundai', 'Mazda', 'Mercedes-Benz', 'Toyota', 'Volkswagen'];
shuffle($arr);
exit(json_encode(array_slice($arr, 0, $nums)));
В качестве сервера можно использовать «Open Server Panel», встроенный в PHP веб-сервер, на базе WSL или любой другой.
2. Создадим HTML файл и поместим в <body>
следующее содержимое:
<input type="number" id="nums" min="1" max="8" value="3">
<button type="button" id="get">Получить список</button>
<ul id="list"></ul>
<script>
function getData() {
const nums = parseInt(document.querySelector('#nums').value);
// URL на который будем отправлять GET запрос
const requestURL = `/examples/ajax/01.php?nums=${nums}`;
const xhr = new XMLHttpRequest();
xhr.open('GET', requestURL);
xhr.onload = function () {
if (xhr.status !== 200) {
return;
}
const response = JSON.parse(xhr.response);
let html = [];
for (let i = 0, length = response.length; i < length; i++) {
html.push(`<li>${response[i]}</li>`);
}
document.querySelector('#list').innerHTML = html.join('');
}
xhr.send();
}
// при нажатию на кнопку
document.querySelector('#get').addEventListener('click', () => {
getData();
});
</script>

В этом примере:
- при нажатии на кнопку вызывается функция
getData()
; - эта функция создаёт AJAX запрос и отправляет его на «
/examples/ajax/01.php
», после получения ответа она обновляет содержимое элемента#list
; - для преобразования JSON в массив используется метод
JSON.parse()
; - изменение содержимого элемента
#list
выполняется с помощьюinnerHTML
.
По умолчанию ожидаемым типом ответа (xhr.responseType
) является строка (""
). Но в этом примере мы получаем ответ в формате JSON, поэтому чтобы его распарсить мы дополнительно используем метод JSON.parse()
:
// xhr.responseType = ''; // по умолчанию
const response = JSON.parse(xhr.response);
Чтобы этого не делать, мы можем с помощью xhr.responseType
указать ожидаемый тип ответа. В этом случае скрипт можно переписать так:
function getData() {
const nums = parseInt(document.querySelector('#nums').value);
// URL на который будем отправлять GET запрос
const requestURL = `/examples/ajax/01.php?nums=${nums}`;
const xhr = new XMLHttpRequest();
xhr.open('GET', requestURL);
xhr.responseType = 'json';
xhr.onload = function () {
if (xhr.status !== 200) {
return;
}
const response = xhr.response;
let html = [];
for (let i = 0, length = response.length; i < length; i++) {
html.push(`<li>${response[i]}</li>`);
}
document.querySelector('#list').innerHTML = html.join('');
}
xhr.send();
}
// при нажатию на кнопку
document.querySelector('#get').addEventListener('click', () => {
getData();
});
xhr.responseType
кроме "text"
(по умолчанию) и "json"
может иметь ещё следующие значения: "arraybuffer"
, "blob"
и "document"
.
Пример синхронного AJAX запроса
Синхронный запрос в отличие от асинхронного, после его отправки и до получения ответа, замораживает веб-страницу, т.е. делает её недоступной для пользователя. Хотя синхронные запросы на сайтах практически не используются, но знать как они создаются лишним не будет.
В качестве примера рассмотрим создания синхронного GET запроса с одним параметром:
Введите ваш вопрос?
<input type="text" id="q" value="Что Такое AJAX и как он работает" style="width: 100%;">
<button type="button" id="send">Отправить вопрос и получить ответ</button>
<div id="result">...</div>
<script>
document.querySelector('#send').addEventListener('click', () => {
let requestURL = new URL('https://itchief.ru/examples/ajax/04.php');
requestURL.searchParams.set('q', document.querySelector('#q').value);
// создание экземпляра объекта XMLHttpRequest
const xhr = new XMLHttpRequest();
// настройка запроса (false - синхронный запрос)
xhr.open('GET', requestURL, false);
// отправка запроса
xhr.send();
// получение ответа и отображение его в #result
document.querySelector('#result').innerHTML = xhr.response;
});
</script>
Содержимое файла 04.php:
<?php
// получим POST данные
$q = filter_var($_GET['q'], FILTER_SANITIZE_STRING);
// сформируем ответ
echo 'Ответ на вопрос «' . $q . '» ...';
Пример AJAX POST запроса
Передача данных с помощью метода POST осуществляется в теле запроса. Другими словами, этот метод используется, когда данные нужно передать в скрытом виде. Метод POST очень часто применяется для отправки форм.
PHP-скрипт:
<?php
// получим POST данные
$firstname = $_POST['firstname'];
$lastname = $_POST['lastname'];
// сформируем ответ
$output = ['firstname' => $firstname, 'lastname' => $lastname];
exit(json_encode($output));
HTML-код:
<form name="user" action="/examples/ajax/02.php" method="post">
<label for="firstname">Имя:</label><input type="text" name="firstname" id="firstname">
<label for="lastname">Фамилия:</label><input type="text" name="lastname" id="lastname">
<button type="submit">Отправить</button>
</form>
<div class="result-wrapper">
Полученные данные:
<ul id="result">...</ul>
</div>
<script>
const elForm = document.querySelector('[name="user"]');
const elFirstname = elForm.querySelector('[name="firstname"]');
const elLastname = elForm.querySelector('[name="lastname"]');
const elResult = document.querySelector('#result');
const requestURL = elForm.action;
function sendForm() {
const firstname = encodeURIComponent(elFirstname.value);
const lastname = encodeURIComponent(elLastname.value);
const formData = 'firstname=' + firstname + '&lastname=' + lastname;
const xhr = new XMLHttpRequest();
xhr.open('POST', requestURL);
xhr.responseType = 'json';
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = () => {
if (xhr.status !== 200) {
return;
}
const response = xhr.response;
elResult.innerHTML = `<ul><li>Имя: <b>${response.firstname}</b></li><li>Фамилия: <b>${response.lastname}</b></li></ul>`;
}
xhr.send(formData);
elResult.textContent = '...';
}
// при отправке формы
elForm.addEventListener('submit', (e) => {
e.preventDefault();
sendForm();
});</script>

Более простой способ получить данные формы – это воспользоваться FormData().
Код, приведённый выше в этом случае можно переписать так:
<form name="user" action="/examples/ajax/03.php" method="post">
<label for="firstname">Имя:</label><input type="text" name="firstname">
<label for="lastname">Фамилия:</label><input type="text" name="lastname">
<button type="submit">Отправить</button>
</form>
<div class="result-wrapper">
Полученные данные:
<ul id="result">...</ul>
</div>
<script>
function sendForm() {
const xhr = new XMLHttpRequest();
xhr.open('POST', document.forms.user.action);
xhr.responseType = 'json';
xhr.onload = () => {
if (xhr.status !== 200) {
return;
}
const response = xhr.response;
document.querySelector('#result').innerHTML = `<li>Имя: <b>${response.firstname}</b></li><li>Фамилия: <b>${response.lastname}</b><li>IP адрес: <b>${response.ip}</b></li>`;
}
let formData = new FormData(document.forms.user);
xhr.send(formData);
document.querySelector('#result').textContent = '...';
}
// при отправке формы
document.forms.user.addEventListener('submit', (e) => {
e.preventDefault();
sendForm();
});
</script>
В php дополнительно добавим код для получения IP-адреса:
<?php
// получим POST данные
$firstname = $_POST['firstname'];
$lastname = $_POST['lastname'];
$ip = $_SERVER['REMOTE_ADDR'];
// сформируем ответ
$output = ['firstname' => $firstname, 'lastname' => $lastname, 'ip' => $ip];
exit(json_encode($output));
Будьте добры, подскажите один момент насчет аякс-запросов к стороннему сайту (не локалхост).
Такой вот код
В отладчике вызывает ошибку:
«Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at … (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).»
Аналогичная ситуация и при испольозвании
Так как через reqbin.com все работает, прричина все-таки не в настройках сервера?
Подскажите пожалуйста что специфичное (нестандартное) передается при асинхронных запросах:
— в заголовках от клиента к серверу и обратно
— в данных от клиента к серверу при POST запросе, и от сервера клиенту в блоке данных
Вопрос связан с тем, что HTTP-сервер самописанный и встроен в программу (бинарник), поэтому использовать примеры на PHP не представляется возможным. Cервер работает напрямую с сокетами, делает разбор и формирование заголовков и данных.
Заранее спасибо.
Ваш пример заработал. Действительно, асинхронные запросы прозрачны для сервера.
Моя ошибка была в том, что я выдавал статус 302, а не 200. Это было связано с тем, что нижеприведенный код срабатывал только на статус 302.
Первое — это нужно получить данные (GET, POST, REQUEST). После этого обычно приступают к проверке данных и того, как они были получены. Если валидация данных прошла не успешно, то действие на сервере обычно прекращают и возвращают результат. В противном случае продолжают дальнейшие действия. Здесь уже вы выполняете действия в зависимости от задачи, опираясь на данные, которые получили. Это может быть выбор информации из базы данных или запись в неё, отправка писем, запись данных в файлы и многое другое. В результате выполнения этого или нет необходимо сформировать ответ и отправить его пользователю. При AJAX формирование ответа обычно осуществляется в формате JSON.
После этого, когда клиент (браузер пользователя) получит ответ от сервера, необходимо его разобрать и вывести пользователю данные или какую-то другую информацию.
Чтобы глубже разобраться в этом разбирайте реальные примеры: Скрипт звёздного рейтинга для сайта, Форма обратной связи и др.
так как реально введенное имя назад не возвращается.
ps
Еще в ваше статье не корректно работает блок развернуть — перекрывает текст ниже, а должен сдвигать вниз
Два раза див закрывал, вместо того, чтобы открывать-закрывать:(
Для того чтобы данная страница (proccesing.php) что-то отобразила ей необходимо передать данные методом POST. Т.е. она не может ничто вывести, если в суперглобальном массиве $_POST не будет ключа nameUser. Другими словами, вам никто не запрещает сделать обычную HTML форму и назначить данный файл для её обработки (без AJAX).
Но если вы хотите чтобы файл proccesing.php выполнялся только для AJAX запросов, то необходимо сделать следующее:
1. Добавить в сценарий JavaScript строчку:
2. Будем его проверять в файле proccesing.php. Если данный заголовок не доступен в этом файле (запустили его не по AJAX), то завершаем его работу.
Мне нужно по нажатию на эту кнопку что бы изображение отсылалось на сервер. В идеале конечно в контроллер отослать как будто через обыкновенную форму.
При этом код JavaScript не нужен.
Как отправлять изображения на сервер можете посмотреть в этой статье: itchief.ru/lessons/php/feedback-form-for-website
Большое спасибо за статью!
А где бы посмотреть подгрузку информации при прокрутке страницы? Т.е. например листаем вниз, добавляются новые посты.
Тут необходимо завести переменную, которая будет отвечать за то, находится ли AJAX запрос в обработке или нет. Например, processing. Т.е. если при прокрутке страницы, значение переменной равно false, то загружаем данные. На момент загрузки данных устанавливаем значение переменной processing, равной true. Это необходимо сделать для того чтобы не сделать кучу запросов пока данные не пришли. Как только данные пришли, устанавливаем переменной значение false и готовы к загрузке новой партии данных с сервера. Другими словами, данная переменная необходима для того чтобы при прокрутке Вы не сделали 1000 запрос к серверу, а только один.
Для простоты приведу решение на jQuery, пояснив каждую строчку кода. Для загрузки данных будем использовать содержимое файла data.txt. Т.е. при прокрутке страницы более чем на 80%, берём данные из файла data.txt и помещаем их в блок div.
Для демонстрации можно создать файл data.txt со следующим содержимым:
Ну и добавить стиль CSS в вышеприведённый документ: