jQuery AJAX — это набор функций библиотеки jQuery для отправки HTTP-запросов из JavaScript без перезагрузки страницы: базовая $.ajax() и сокращения $.get(), $.post(), $.getJSON(), .load(). Под капотом они работают через встроенный в браузер объект XMLHttpRequest и возвращают объект jqXHR, на который вешают обработчики .done(), .fail() и .always().
Содержание
- Что есть что: AJAX, XHR, jqXHR, fetch
- Минимальный рабочий пример
- Разбор $.ajax: главные параметры
- Обработчики: .done, .fail, .always и .then
- Сокращения: $.get, $.post, $.getJSON, .load
- Типичная ошибка: JSON уходит как форма
- Тот же код на fetch
- Если не получилось
- Безопасность запросов
- Выводы
- Где применяется / связь с практикой
- FAQ
jQuery на 2026 год — библиотека для поддержки существующего кода: в новых проектах тот же запрос пишут на встроенном fetch. Поэтому ниже каждый прием показан в двух вариантах. Примеры проверены на jQuery 4.0.0 и Node.js 24 (сентябрь 2026).
Что есть что: AJAX, XHR, jqXHR, fetch
Эти слова часто смешивают, хотя они обозначают разные уровни.
| Термин | Что это | Где живет |
|---|---|---|
| AJAX | Подход: запрос из скрипта в фоне и обновление части страницы. Не библиотека и не протокол | Идея, название с 2005 года |
XMLHttpRequest (XHR) |
Встроенный браузерный API для HTTP-запросов, событийный | Браузер |
jqXHR |
Обертка jQuery над XHR с методами промиса (.done, .fail, .then) |
jQuery |
fetch |
Современный встроенный API на промисах | Браузер, Node.js 18+ |
Буква X в AJAX исторически означает XML, но сегодня почти всегда передают JSON. Сам запрос остается обычным HTTP: сервер не знает, что его отправил jQuery.
Минимальный рабочий пример
Нужны сервер и страница. Сервер ниже отдает список курсов по GET, принимает запись на курс по POST (только в формате JSON) и раздает статику. Положите jquery.min.js и index.html в папку public рядом с сервером.
// server.js - учебный сервер: node server.js, затем http://localhost:3000
const http = require("node:http");
const fs = require("node:fs");
const path = require("node:path");
const courses = [{ id: 1, title: "JavaScript Developer. Basic" }];
function sendJson(res, status, obj) {
res.writeHead(status, { "Content-Type": "application/json; charset=utf-8" });
res.end(JSON.stringify(obj));
}
http.createServer((req, res) => {
if (req.method === "GET" && req.url === "/api/courses") {
return sendJson(res, 200, courses);
}
if (req.url === "/api/slow") { // для проверки таймаута
return setTimeout(() => sendJson(res, 200, { late: true }), 3000);
}
if (req.method === "POST" && req.url === "/api/signup") {
let body = "";
req.on("data", (chunk) => (body += chunk));
return req.on("end", () => {
const type = req.headers["content-type"] || "";
if (!type.startsWith("application/json")) {
return sendJson(res, 415, { error: "ожидаю JSON", got: type });
}
let data;
try { data = JSON.parse(body); } catch { return sendJson(res, 400, { error: "битый JSON" }); }
if (!data.email) return sendJson(res, 422, { error: "нет email" });
sendJson(res, 201, { ok: true, email: data.email });
});
}
// статика: index.html и jquery.min.js из папки public
const file = req.url === "/" ? "index.html" : path.basename(req.url);
fs.readFile(path.join(__dirname, "public", file), (err, content) => {
if (err) return sendJson(res, 404, { error: "not found" });
const type = file.endsWith(".js") ? "text/javascript" : "text/html; charset=utf-8";
res.writeHead(200, { "Content-Type": type });
res.end(content);
});
}).listen(3000, () => console.log("http://localhost:3000"));
Страница делает два запроса: GET при загрузке и POST при отправке формы.
<!doctype html>
<html lang="ru">
<head><meta charset="utf-8"><title>jQuery AJAX</title></head>
<body>
<ul id="courses"></ul>
<form id="signup">
<input name="email" value="student@example.com">
<button>Записаться</button>
</form>
<p id="status"></p>
<script src="/jquery.min.js"></script>
<script>
// 1. GET: получить JSON и вывести список
$.ajax({ url: "/api/courses", method: "GET", dataType: "json", timeout: 5000 })
.done(function (courses) {
courses.forEach(function (c) {
$("<li>").text(c.title).appendTo("#courses"); // .text(), не .html()
});
})
.fail(function (jqXHR, textStatus) {
$("#status").text("Ошибка загрузки: " + textStatus + " " + jqXHR.status);
});
// 2. POST: отправить форму как JSON без перезагрузки страницы
$("#signup").on("submit", function (event) {
event.preventDefault();
$.ajax({
url: "/api/signup",
method: "POST",
contentType: "application/json",
data: JSON.stringify({ email: $(this).find("[name=email]").val() }),
dataType: "json"
})
.done(function (data, textStatus, jqXHR) {
$("#status").text(jqXHR.status + ": записан " + data.email);
})
.fail(function (jqXHR) {
$("#status").text(jqXHR.status + ": " + (jqXHR.responseJSON ? jqXHR.responseJSON.error : jqXHR.statusText));
})
.always(function () {
console.log("запрос завершен");
});
});
</script>
</body>
</html>
Запустите node server.js и откройте http://localhost:3000. В списке появится «JavaScript Developer. Basic». После нажатия кнопки в абзаце будет 201: записан student@example.com, в консоли — «запрос завершен». Если стереть email и отправить снова, сработает .fail: 422: нет email. Страница при этом не перезагружается.
Открывать index.html двойным кликом (адрес file://) нельзя: запросы к /api/... уйдут не на сервер, и пример не заработает.
Разбор $.ajax: главные параметры
$.ajax() принимает объект настроек. Остальные функции jQuery для запросов — сокращенные вызовы той же $.ajax().
| Параметр | Что делает | В примере |
|---|---|---|
url |
Адрес запроса | "/api/courses" |
method |
HTTP-метод (старое имя — type, работает как синоним) |
"POST" |
data |
Данные: объект кодируется как форма a=1&b=2, строка уходит как есть |
JSON.stringify(...) |
contentType |
Заголовок Content-Type тела запроса. По умолчанию — форма |
"application/json" |
dataType |
Как разобрать ответ: json, text, html, script |
"json" |
timeout |
Сколько миллисекунд ждать до ошибки timeout |
5000 |
headers |
Дополнительные заголовки, например CSRF-токен | — |
Важно различать contentType и dataType: первый описывает то, что вы отправляете, второй — как jQuery разберет ответ.
Обработчики: .done, .fail, .always и .then
.done(data, textStatus, jqXHR) срабатывает при коде 2xx и успешном разборе ответа. .fail(jqXHR, textStatus, errorThrown) — при коде 4xx/5xx, таймауте, обрыве сети и ошибке разбора. .always — в любом случае. jqXHR поддерживает и .then(), поэтому цепочки промисов тоже работают: $.getJSON("/api/courses").then(d => d.length) вернет 1.
Опции success, error и complete внутри объекта настроек по-прежнему поддерживаются. А вот одноименные методы у результата убрали в jQuery 3.0, и старый код падает на 4.0.0 так:
TypeError: $.ajax(...).success is not a function
Исправление — заменить .success() на .done(), .error() на .fail(), .complete() на .always().
Сокращения: $.get, $.post, $.getJSON, .load
| Сокращение | Что делает | Эквивалент через $.ajax |
|---|---|---|
$.get(url, data) |
GET, параметры в строку запроса | method: "GET" |
$.post(url, data) |
POST, тело как форма | method: "POST" |
$.getJSON(url) |
GET с разбором JSON | dataType: "json" |
$("#box").load(url) |
GET и вставка HTML ответа в элемент; если вторым аргументом передан объект, уходит POST | dataType: "html" + .html() |
$.getScript(url) |
Загружает и выполняет JS | dataType: "script" |
Сокращения удобны, пока хватает умолчаний. В привычной позиционной форме $.post(url, data, success, dataType) параметра contentType нет, и это главный источник ошибки ниже. Объектная форма $.post({ url, data, contentType: "application/json" }) его принимает, но это уже тот же $.ajax с method: "POST".
Типичная ошибка: JSON уходит как форма
Неверно: передать объект или JSON-строку без contentType.
$.post("/api/signup", JSON.stringify({ email: "b@example.com" }), null, "json")
.fail(function (jqXHR) { console.log(jqXHR.status, jqXHR.responseText); });
Фактический результат на нашем сервере:
415 {"error":"ожидаю JSON","got":"application/x-www-form-urlencoded; charset=UTF-8"}
Тело ушло строкой JSON, но с заголовком формы, и сервер его отверг. Если бы в data был объект, jQuery закодировал бы его как email=b%40example.com — сервер получил бы тот же 415. Исправление — $.ajax (или объектная форма $.post) с contentType: "application/json" и JSON.stringify, как в основном примере: такой запрос возвращает 201.
Тот же код на fetch
fetch встроен в браузеры и в Node.js 18+, библиотека не нужна. Ключевое отличие: промис fetch отклоняется только при сетевой ошибке или отмене. Ответ 404 или 422 считается успешным, поэтому код ответа проверяют сами через response.ok.
// fetch-demo.mjs - те же запросы на fetch (Node 18+ или браузер)
const base = "http://localhost:3000"; // в браузере на той же странице - просто ""
async function getJson(url, options = {}) {
const response = await fetch(base + url, {
signal: AbortSignal.timeout(2000), // аналог timeout: 2000 в $.ajax
...options,
});
const data = await response.json().catch(() => null);
if (!response.ok) { // fetch НЕ отклоняет промис на 4xx/5xx
throw new Error(`${response.status}: ${data?.error ?? response.statusText}`);
}
return data;
}
const courses = await getJson("/api/courses");
console.log("GET:", courses.map((c) => c.title));
const created = await getJson("/api/signup", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: "student@example.com" }),
});
console.log("POST:", created);
for (const [url, options] of [
["/api/signup", { method: "POST", headers: { "Content-Type": "application/json" }, body: "{}" }],
["/api/slow", {}],
]) {
try {
await getJson(url, options);
} catch (error) {
console.log("Ошибка:", error.name, error.message);
}
}
При запущенном сервере node fetch-demo.mjs выводит:
GET: [ 'JavaScript Developer. Basic' ]
POST: { ok: true, email: 'student@example.com' }
Ошибка: Error 422: нет email
Ошибка: TimeoutError The operation was aborted due to timeout
Без проверки response.ok запрос с 422 прошел бы как успешный: fetch вернул бы ok: false, status: 422 без исключения.
| Поведение | jQuery $.ajax |
fetch |
|---|---|---|
| Ответ 4xx/5xx | Уходит в .fail |
Промис выполняется, проверять response.ok |
| Разбор JSON | По dataType или заголовку ответа |
Явно: await response.json() |
| Отправка JSON | contentType + JSON.stringify |
Заголовок + JSON.stringify |
| Таймаут | Опция timeout, статус timeout |
AbortSignal.timeout(ms), ошибка TimeoutError |
| Отмена | jqXHR.abort() |
AbortController |
| Зависимость | Библиотека в полной сборке | Встроен |
Если не получилось
$.ajax is not a function. Подключена slim-сборка (jquery.slim.min.js), в ней нет AJAX, а в jQuery 4 — еще и$.Deferred. Нужна полнаяjquery.min.js..failсparsererrorи кодом 200. УказанdataType: "json", а сервер вернул HTML (часто страницу ошибки или логина). В V8 текст такой:SyntaxError: Unexpected token '<', "<!doctype "... is not valid JSON. Проверьте ответ во вкладке Network.- Код 0 и статус
timeoutилиerror. Сервер не ответил за времяtimeout, соединение оборвалось или запрос заблокирован. Смотрите консоль и Network. - Ошибка CORS в консоли. Запрос идет на другой домен, а сервер не разрешил его заголовком
Access-Control-Allow-Origin. Чинится на сервере, не в jQuery. - Сервер получил пустое тело или 415. Не совпал формат: см. раздел о
contentTypeвыше.
Безопасность запросов
Ответ сервера выводите через .text(), а не .html(): строка из базы, вставленная как HTML, может выполнить чужой скрипт (XSS). По той же причине .load() и dataType: "script" применяйте только к своему серверу.
Для POST-запросов с сессионными cookie сервер должен проверять CSRF-токен, а клиент — передавать его, например через headers или один раз в $.ajaxSetup(). CORS — это не защита API: он лишь говорит браузеру, каким сайтам можно читать ответ, а запросы из curl или с сервера он не ограничивает.
Учебный сервер выше не ограничивает размер тела, не проверяет права и не пишет журнал. В production это нужно добавить.
Выводы
- jQuery AJAX — обертка над
XMLHttpRequest:$.ajax()как основа,$.get,$.post,$.getJSON,.loadкак сокращения. - Результат запроса обрабатывают через
.done,.fail,.alwaysили.then; методы.success()и.error()удалены в jQuery 3.0. - Чтобы отправить JSON, нужны
contentType: "application/json"иJSON.stringify;$.postпо умолчанию шлет форму. - В новом коде тот же запрос пишут на
fetch, но проверяютresponse.okсами: ответ 4xx/5xx промис не отклоняет.
Где применяется / связь с практикой
jQuery AJAX встречается в поддержке сайтов на CMS, админках и старых интерфейсах: разработчику нужно читать такой код, чинить его и постепенно переводить на fetch. Что умеет сама библиотека помимо запросов, разобрано в статье библиотека jQuery: описание и области применения.
Освойте тему на практике
Асинхронный JavaScript, промисы, async/await и работу с сетью системно проходят на курсе «JavaScript-разработчик. Базовый уровень». Бесплатно разобрать отдельные темы с преподавателями можно на открытых уроках Otus.
FAQ
Можно ли сделать синхронный запрос через async: false?
Технически опция есть, но синхронный XHR в основном потоке браузеры считают устаревшим: он замораживает страницу. Используйте .done или await.
Как показать прогресс загрузки файла?
Через XHR: в $.ajax передают функцию xhr, которая возвращает XMLHttpRequest с обработчиком upload.onprogress. У fetch стандартного события прогресса отправки нет.
Стоит ли убирать jQuery из работающего проекта ради fetch?
Только если есть причина: размер бандла, переход на фреймворк, удаление другого legacy. Переписывать запросы по одному безопасно — оба способа работают на одной странице.



