www.jQueryBook.ru - jQuery документация

 

 

 

 



Ajax в jQuery: $.ajax, $.get, $.post и отправка форм без перезагрузки

Опубликовано: 26.09.2026 · Обновлено: 26.09.2026 · Актуально для jQuery 3.7.1 и 4.0.0

В основе всех Ajax-запросов jQuery лежит один метод — $.ajax(). $.get(), $.post(), $.getJSON() и .load() — это его короткие обёртки для частых случаев, под капотом они вызывают тот же $.ajax() с готовым набором настроек. Результат любого из них — объект jqXHR: он реализует интерфейс Promise/A+, поэтому обрабатывать ответ можно через .done()/.fail()/.always() (или совместимый с ними .then()), либо через async/await, если код построен на промисах.

Короткие методы и $.ajax()

Все Ajax-функции jQuery сводятся к одному универсальному методу — $.ajax(). Остальные — сокращения для типовых случаев: меньше кода, но и меньше гибкости, часть настроек в них зашита заранее.

МетодЧто делаетЭквивалент через $.ajax()
$.get(url, data, success, dataType)GET-запрос, самый частый случай — получить данные$.ajax({ url, method: "GET", data, success, dataType })
$.post(url, data, success, dataType)POST-запрос — отправить данные на сервер$.ajax({ url, method: "POST", data, success, dataType })
$.getJSON(url, data, success)GET-запрос с заранее заданным dataType: "json"$.ajax({ url, dataType: "json", data, success })
$.getScript(url, success)Загружает JS-файл и выполняет его$.ajax({ url, dataType: "script", success })
.load(url, data, complete)Загружает HTML с сервера и вставляет в выбранные элементыGET/POST через $.ajax() + .html() над результатом; поддерживает селектор внутри строки: .load("/page.html #block")

С версий 1.12/2.2 у $.get() и $.post() есть ещё один вариант вызова — единственный объект настроек, как в $.ajax(): $.get({ url: "/api/users/42", dataType: "json", headers: {...} }). Обратите внимание: url здесь внутри объекта. Если написать $.get(url, { dataType: "json" }), второй аргумент будет считаться данными запроса и уйдёт в строку запроса как ?dataType=json. Нужна настройка вне короткой сигнатуры (заголовки, timeout) — берите объектный вариант или сразу $.ajax().

// Три варианта одного и того же GET-запроса
$.get("/api/users/42", function (user) {
  console.log(user.name);
});

$.get({ url: "/api/users/42", dataType: "json" })
  .done(function (user) {
    console.log(user.name);
  });

$.ajax({
  url: "/api/users/42",
  method: "GET",
  dataType: "json"
}).done(function (user) {
  console.log(user.name);
});

.load() стоит особняком: это единственный метод из таблицы, который вызывается не на $/jQuery, а на выборке элементов — $("#content").load("/page.html"). Он всегда работает с HTML-ответом и не принимает dataType.

Настройки $.ajax(), которые нужны чаще всего

$.ajax() принимает один объект настроек. Параметров у него около тридцати, но в повседневной работе почти всегда нужны только эти:

ОпцияТип / по умолчаниюЗачем нужна
urlстрокаАдрес запроса. Единственный обязательный параметр, если не передан первым аргументом.
methodстрока, по умолчанию "GET"HTTP-метод: "GET", "POST", "PUT", "DELETE". Добавлен в 1.9 как более понятное имя для старой type — обе работают в 3.7 и 4.0, но пишите method.
dataобъект / строка / массивДанные запроса. Для GET уходят в строку запроса, для остальных методов — в тело (формат зависит от contentType).
dataTypeстрока, по умолчанию — «умное угадывание» по заголовку ответаОжидаемый формат ответа: "json", "html", "script", "xml", "text". Указывайте явно — угадывание не всегда надёжно.
contentTypeстрока, по умолчанию "application/x-www-form-urlencoded; charset=UTF-8"Формат тела запроса. Для JSON меняйте на "application/json" вручную — сам jQuery это не делает.
processDataбулево, по умолчанию trueАвтоматически превращать data в строку. Для FormData нужно false, иначе jQuery попытается сериализовать её как обычный объект.
headersобъект, по умолчанию {}Дополнительные заголовки — токены авторизации, CSRF-токен.
timeoutчисло миллисекундЧерез сколько считать запрос неудавшимся. 0 (по умолчанию) — без ограничения.
cacheбулево, по умолчанию true, false для "script" и "jsonp"Разрешить браузеру кешировать GET-запрос. Для всегда свежих данных ставьте false.
xhrFields.withCredentialsбулево, по умолчанию falseОтправлять cookies и заголовки авторизации в кросс-доменных запросах.
$.ajax({
  url: "/api/orders",
  method: "POST",
  data: JSON.stringify({ productId: 17, qty: 2 }),
  contentType: "application/json",
  dataType: "json",
  headers: { "X-Requested-With": "XMLHttpRequest" },
  timeout: 8000,
  xhrFields: { withCredentials: true }
})
  .done(function (order) {
    console.log("заказ создан", order.id);
  })
  .fail(function (jqXHR, textStatus) {
    console.error("не удалось создать заказ:", textStatus);
  });

Полный список опций — на странице $.ajax(). Задать значения по умолчанию сразу для всех запросов можно через $.ajaxSetup() — но осторожно, это глобальная настройка, она повлияет и на сторонние плагины.

Обработка ответа: .done/.fail/.always и .then

$.ajax() и все его обёртки возвращают объект jqXHR — надстройку над XMLHttpRequest, совместимую с интерфейсом Promises/A+. Есть два способа подписаться на результат.

Через колбэки в настройках — success, error, complete. Они по-прежнему работают в jQuery 3.7 и 4.0, никто их не убирал:

$.ajax({
  url: "/api/profile",
  success: function (data, textStatus, jqXHR) {
    console.log("получено", data);
  },
  error: function (jqXHR, textStatus, errorThrown) {
    console.error("ошибка", textStatus);
  },
  complete: function (jqXHR, textStatus) {
    console.log("запрос завершён в любом случае");
  }
});

Через методы jqXHR — .done(), .fail(), .always() — те же три случая, но можно вызывать цепочкой уже после того, как получили результат запроса, и вешать несколько обработчиков на один и тот же jqXHR:

$.ajax("/api/profile")
  .done(function (data, textStatus, jqXHR) {
    console.log("получено", data);
  })
  .fail(function (jqXHR, textStatus, errorThrown) {
    console.error("ошибка:", textStatus, errorThrown);
  })
  .always(function () {
    console.log("запрос завершён в любом случае");
  });

Не путайте колбэк success в настройках и метод jqXHR.success(). Колбэк в объекте настроек работает и сейчас. А вот одноимённые методы самого jqXHR (jqXHR.success(fn), jqXHR.error(fn), jqXHR.complete(fn)) — это специальный случай, удалённый в jQuery 3.0 как источник путаницы «это же не настоящий Deferred». Старый код вида $.ajax(...).success(fn) на 3.0+ упадёт с TypeError — замените на .done(fn).

Аргументы у .done() и .fail() расположены зеркально не случайно: .done(data, textStatus, jqXHR) — данные первыми, потому что это главное, что нужно при успехе; .fail(jqXHR, textStatus, errorThrown) — сам jqXHR первым, потому что при ошибке распарсенных данных обычно нет, а нужен доступ к статусу ответа (jqXHR.status) и телу ошибки (jqXHR.responseText или jqXHR.responseJSON, если сервер вернул JSON с описанием ошибки).

Поскольку jqXHR — thenable-объект, с ним работает и .then(), и, что удобнее в современном коде, async/await:

async function loadProfile() {
  try {
    const data = await $.ajax({ url: "/api/profile", dataType: "json" });
    console.log("получено", data);
  } catch (jqXHR) {
    // При отклонении промиса await получает jqXHR, а не объект Error
    console.error("ошибка:", jqXHR.status, jqXHR.statusText);
  }
}

jqXHR.status === 0 не значит «сервер ответил нулём» — это значит, что ответ вообще не получен: .abort(), обрыв сети, истёкший timeout или блокировка CORS ещё до ответа. Различить причины помогает textStatus ("timeout", "abort", "error") — подробности при CORS смотрите в консоли браузера, а не в аргументах колбэка.

JSON: получить и отправить

Получение и отправка JSON — разные по механике вещи, их часто путают.

Получить JSON — указать dataType: "json" в $.ajax() или использовать $.getJSON(). jQuery сам распарсит текст ответа и отдаст в колбэк готовый объект:

$.getJSON("/api/products", { category: "shoes" })
  .done(function (products) {
    console.log(products.length, "товаров");
  })
  .fail(function (jqXHR, textStatus) {
    // Частая причина parsererror здесь — пустое тело ответа
    console.error(textStatus);
  });

Отправить JSON — самостоятельно сериализовать объект и указать тип содержимого. По умолчанию $.ajax() отправляет data как application/x-www-form-urlencoded — объект { name: "Иван", age: 30 } без настроек уйдёт строкой name=%D0%98%D0%B2%D0%B0%D0%BD&age=30, а не JSON:

// НЕПРАВИЛЬНО: сервер, ожидающий JSON, получит form-urlencoded тело
$.ajax({
  url: "/api/products",
  method: "POST",
  data: { name: "Кроссовки", price: 4990 }
});

// ПРАВИЛЬНО: явная сериализация и content-type
$.ajax({
  url: "/api/products",
  method: "POST",
  data: JSON.stringify({ name: "Кроссовки", price: 4990 }),
  contentType: "application/json",
  dataType: "json" // формат ответа, а не запроса
});

Это самая частая причина «сервер получает пустой объект» в связках jQuery + JSON API: разработчик меняет dataType, думая, что это управляет и форматом отправки, но dataType — только про формат ответа. За формат тела запроса отвечают contentType и ручной JSON.stringify().

Отправка формы

Базовый сценарий — отправить форму без перезагрузки страницы. Сначала — обработчик submit с preventDefault(), чтобы браузер не сделал стандартную отправку и переход:

$("#feedback-form").on("submit", function (event) {
  event.preventDefault();
  var $form = $(this);
  var $btn = $form.find("button[type=submit]");

  $btn.prop("disabled", true);

  $.ajax({
    url: $form.attr("action"),
    method: "POST",
    data: $form.serialize(), // "name=..&email=..&message=.."
    dataType: "json"
  })
    .done(function (response) {
      $form[0].reset();
    })
    .fail(function (jqXHR) {
      var errors = jqXHR.responseJSON && jqXHR.responseJSON.errors;
      showFormErrors($form, errors || { _general: "Не удалось отправить форму" });
    })
    .always(function () {
      $btn.prop("disabled", false);
    });
});

.serialize() собирает поля формы в строку вида a=1&b=2. Если нужен не строковый, а объектный результат — есть .serializeArray(), возвращающая массив { name, value } по каждому полю. Оба метода учитывают только поля с атрибутом name и пропускают отключённые и невыбранные radio/checkbox.

Блокировка кнопки на время запроса — обязательная деталь: без неё двойной клик или медленное соединение отправляют форму дважды. Снимать блокировку нужно в .always(), а не в .done(), иначе при ошибке кнопка останется заблокированной навсегда.

Ошибки валидации с сервера обычно приходят с кодом 4xx — это тоже .fail(), а не .done(). Распарсенный JSON из тела ошибки jQuery кладёт в jqXHR.responseJSON, либо доступен как текст в jqXHR.responseText.

Отправка файлов требует другого набора настроек: содержимое формы собирается не в строку, а в FormData — объект, умеющий нести бинарные данные:

$("#upload-form").on("submit", function (event) {
  event.preventDefault();
  var formData = new FormData(this); // включая поля <input type="file">

  $.ajax({
    url: "/api/upload",
    method: "POST",
    data: formData,
    processData: false, // не превращать FormData в строку
    contentType: false, // не задавать Content-Type самим — это сделает браузер
    dataType: "json"
  }).done(function (response) {
    console.log("файл загружен:", response.url);
  });
});

processData: false и contentType: false обязательны вместе: иначе jQuery подставит application/x-www-form-urlencoded вместо нужного multipart/form-data; boundary=..., и сервер не разберёт форму.

Таймауты, повтор и отмена

Опция timeout обрывает запрос, если ответ не пришёл вовремя, и вызывает .fail() с textStatus === "timeout":

$.ajax({ url: "/api/slow-report", timeout: 5000 })
  .fail(function (jqXHR, textStatus) {
    if (textStatus === "timeout") {
      console.warn("сервер не ответил за 5 секунд");
    }
  });

jqXHR также реализует метод .abort() — им можно отменить запрос вручную в любой момент до завершения:

var request = $.ajax({ url: "/api/report" });

$("#cancel-btn").on("click", function () {
  request.abort();
});

Практическая задача, где отмена нужна почти всегда, — живой поиск по мере ввода: без защиты от гонки более медленный старый ответ может прийти позже нового и затереть актуальный результат:

var currentSearch = null;

$("#search").on("input", function () {
  var query = this.value;

  if (currentSearch) {
    currentSearch.abort(); // отменяем предыдущий незавершённый запрос
  }

  currentSearch = $.ajax({
    url: "/api/search",
    data: { q: query },
    dataType: "json"
  }).done(function (results) {
    renderResults(results);
  });
});

Отменённый через .abort() запрос тоже вызовет .fail() с textStatus === "abort" — это ожидаемо, и такую ошибку в интерфейсе показывать не нужно, достаточно её игнорировать в обработчике.

CORS, cookies и CSRF

CORS (Cross-Origin Resource Sharing) настраивается не в jQuery. Разрешение или запрет запроса с другого домена определяет сервер: он должен вернуть заголовки Access-Control-Allow-Origin (и при необходимости Access-Control-Allow-Credentials, Access-Control-Allow-Headers). Без них браузер заблокирует ответ независимо от кода на jQuery — в консоли ошибка CORS, а в .fail() — статус 0 без подробностей.

На стороне jQuery настраивается только одно — отправлять ли учётные данные (cookies, заголовки авторизации) вместе с кросс-доменным запросом:

$.ajax({
  url: "https://api.example.com/orders",
  xhrFields: { withCredentials: true }
});

Ловушка: при withCredentials: true сервер обязан вернуть Access-Control-Allow-Origin с конкретным доменом, а не * — со звёздочкой браузер откажется принимать ответ. Это ограничение спецификации Fetch/CORS, а не jQuery.

CSRF-токен. Для запросов, которые меняют данные (POST/PUT/DELETE), большинство серверных фреймворков требует передавать защитный токен в заголовке. Общий принцип: токен кладут в <meta>-тег при рендере страницы, а на клиенте читают его и добавляют в заголовки всех запросов через $.ajaxSetup():

var csrfToken = $('meta[name="csrf-token"]').attr("content");

$.ajaxSetup({
  headers: { "X-CSRF-Token": csrfToken }
});

// Теперь любой $.ajax()/$.post() на странице отправит этот заголовок автоматически

Имя заголовка и meta-тега зависит от бэкенда — принцип «токен из meta в заголовок каждого запроса» общий. Если глобальный $.ajaxSetup() нежелателен (часть запросов идёт на сторонние домены), заголовок можно добавлять точечно через beforeSend у конкретного запроса.

Глобальные события Ajax

Кроме колбэков конкретного запроса, jQuery рассылает глобальные события на все Ajax-запросы страницы (отключаются опцией global: false). Подписываются на них через $(document).on("ajaxStart", …) и т. п. Одноимённые методы-шорткаты (.ajaxStart(), .ajaxStop(), .ajaxError() и др.) с jQuery 3.5 считаются устаревшими — работают, но в новом коде используйте .on():

СобытиеКогда срабатываетТипичное применение
ajaxStartНачался первый из одновременных Ajax-запросовПоказать глобальный индикатор загрузки
ajaxStopЗавершились все текущие запросыСкрыть индикатор загрузки
ajaxErrorЛюбой запрос завершился с ошибкойЦентрализованное логирование/уведомление об ошибках
ajaxCompleteЛюбой запрос завершился (успех или ошибка)Общая статистика, аналитика запросов
ajaxSuccessЛюбой запрос завершился успешноОбновление кеша/меток «последняя синхронизация»
ajaxSendПеред отправкой любого запросаОбщая точка для логирования исходящих запросов
$(document)
  .on("ajaxStart", function () {
    $("#global-loader").show();
  })
  .on("ajaxStop", function () {
    $("#global-loader").hide();
  })
  .on("ajaxError", function (event, jqXHR, settings, error) {
    console.error("Ajax-запрос упал:", settings.url, error);
  });

Полный список Ajax-методов, включая низкоуровневые $.ajaxPrefilter() и $.ajaxTransport(), — на странице все Ajax-методы. Глобальными событиями удобно закрывать сквозную логику, но не стоит злоупотреблять: несколько независимых виджетов со своим ajaxError легко превращаются в дублирующиеся уведомления об одной и той же ошибке.

Что изменилось в jQuery 4.0 для Ajax

Релиз jQuery 4.0.0 (январь 2026 года) сделал несколько неявных прежде вещей явными — по историческим причинам безопасности:

  • JSON больше не превращается в JSONP автоматически. Раньше dataType: "json" с параметром обратного вызова в URL мог незаметно обернуться в JSONP-запрос. В 4.0 нужен явный dataType: "jsonp" — неявное превращение убрано как риск выполнения чужого кода без ведома разработчика. Для новых интеграций вместо JSONP лучше обычный CORS-запрос.
  • Скрипты не выполняются без явного dataType: "script". 3.0 уже запрещал это для кросс-доменных запросов; 4.0 распространил ограничение и на запросы в пределах одного домена. Нужен $.getScript() или dataType: "script".
  • Транспорт скриптов теперь всегда использует тег <script>, а не только для кросс-доменных запросов, как раньше. При строгом CSP стоит перепроверить, что политика разрешает нужные источники скриптов.
  • Поддержка FormData и бинарных данных в data встроена в ядро (по руководству по обновлению это может изменить порядок вызова префильтров). Если код должен работать и на 3.x, продолжайте явно указывать processData: false, contentType: false — на 4.0 это не мешает.

Подробный разбор остальных изменений библиотеки, не касающихся Ajax, — в статье что изменилось в jQuery 4.0.

Частые ошибки

СимптомПричинаРешение
parsererror при статусе 200Указан dataType: "json", а тело ответа пустое или не является валидным JSONПроверить фактическое тело ответа; возвращать с сервера {} вместо пустой строки, либо не задавать dataType для пустых ответов
jqXHR.status === 0 без деталейЗапрос не дошёл до сервера: обрыв сети, CORS-блокировка, .abort()Смотреть вкладку «Сеть» в devtools — там видна реальная причина
Ошибка CORS в консолиСервер не отправил Access-Control-Allow-OriginНастраивается на сервере, а не в jQuery
Форма перезагружает страницуВ обработчике submit не вызван event.preventDefault()Добавить event.preventDefault() первой строкой обработчика
Форма отправляется дваждыКнопка не блокируется на время запросаБлокировать кнопку в начале обработчика, снимать в .always()
Объект в data уходит как form-urlencoded вместо JSONНе вызван JSON.stringify(), не изменён contentTypedata: JSON.stringify(obj), contentType: "application/json"
GET-запрос возвращает старые данныеБраузер отдаёт закешированный ответУказать cache: false в настройках запроса

То же на fetch

Нативный fetch() решает ту же задачу иначе: он ближе к «сырому» HTTP и не угадывает формат данных за вас.

Что нужноjQueryfetch
GET-запрос с JSON-ответом$.getJSON(url)fetch(url).then(r => r.json())
Реакция на HTTP-ошибку (4xx/5xx)Автоматически идёт в .fail()fetch отклоняет промис только при сетевой ошибке; статус 4xx/5xx — это «успешный» resolve, ошибку нужно проверять вручную по response.ok
Отправка JSONdata: JSON.stringify(obj), contentType: "application/json"body: JSON.stringify(obj), headers: { "Content-Type": "application/json" }
Отмена запросаjqXHR.abort()AbortController + signal в опциях
Отправка формы с файламиdata: new FormData(form), processData: false, contentType: falsebody: new FormData(form) — fetch сам не выставляет Content-Type для FormData

Переход на fetch оправдан там, где jQuery остаётся только ради Ajax-слоя. Подробнее о соответствиях jQuery и нативного JS — в статье jQuery и чистый JavaScript; о событии submit и отправке форм — в статьях события в jQuery: .on() и .off() и формы в jQuery.

Чек-лист

  • Для типовых запросов — короткие методы ($.get, $.post, $.getJSON), для нестандартных настроек (заголовки, таймаут, отмена, JSON-тело) — сразу $.ajax().
  • Обрабатывать результат через .done()/.fail()/.always() (или async/await), а не через методы jqXHR.success()/.error() — их убрали в jQuery 3.0.
  • Для JSON-тела запроса — обязательно JSON.stringify() и contentType: "application/json"; один dataType: "json" отвечает только за формат ответа.
  • Файлы — через FormData с processData: false, contentType: false вместе.
  • Кнопку отправки формы — блокировать на время запроса, снимать блокировку в .always().
  • Живой поиск и другие запросы, которые могут перекрываться, — хранить jqXHR и вызывать .abort() у предыдущего перед новым запросом.
  • CORS настраивается на сервере; на клиенте — только xhrFields.withCredentials, если нужны cookies кросс-доменно.
  • В jQuery 4.0 JSONP и выполнение скриптов через Ajax требуют явного dataType — неявных автопревращений больше нет.

Частые вопросы

Чем $.post() отличается от $.ajax()?

Ничем принципиальным — $.post(url, data, success, dataType) это сокращённая запись $.ajax({ url: url, method: "POST", data: data, success: success, dataType: dataType }). Внутри $.post() вызывает тот же $.ajax(), просто с меньшим числом аргументов и заранее заданным методом. Если нужны настройки, которых нет в сокращённой сигнатуре (заголовки, timeout, contentType), используйте $.ajax() напрямую или объектный синтаксис $.post({ url: url, data: data, timeout: 5000 }) — единственный аргумент-объект настроек, доступный с jQuery 1.12/2.2.

Почему срабатывает .fail(), хотя сервер вернул статус 200?

Чаще всего дело в dataType. Если явно или неявно (через «intelligent guess» по заголовку ответа) ожидается json, а тело ответа пустое или не является валидным JSON, jQuery не может его распарсить и вызывает .fail() с textStatus === "parsererror", хотя HTTP-статус успешный. Проверьте фактическое тело ответа во вкладке «Сеть» и либо возвращайте с сервера корректный JSON (например, {} вместо пустой строки), либо не указывайте dataType: "json" для ответов без тела.

Как отправить файл через Ajax в jQuery?

Собрать FormData и отключить автоматическую обработку данных: $.ajax({ url, method: "POST", data: new FormData(form), processData: false, contentType: false }). processData: false запрещает jQuery сериализовать FormData в строку, а contentType: false — не выставлять свой заголовок, чтобы браузер сам подставил multipart/form-data с правильным boundary. Если задать contentType вручную, boundary потеряется и сервер не разберёт форму.

Как отправить JSON, а не form-urlencoded?

Данные нужно сериализовать самостоятельно и указать тип содержимого: $.ajax({ url, method: "POST", data: JSON.stringify(obj), contentType: "application/json", dataType: "json" }). Если передать обычный объект в data без JSON.stringify(), jQuery по умолчанию превратит его в строку вида key=value&key2=value2 с contentType: "application/x-www-form-urlencoded" — это самая частая причина, почему сервер, ожидающий JSON, получает пустое тело или падает с ошибкой парсинга.

success или done — что использовать?

Колбэк success в настройках $.ajax() работает и в jQuery 4.0, он никуда не делся. Но начиная с 3.0 у самого jqXHR методы .success()/.error()/.complete() удалены — это разные вещи, и путаница между ними встречается часто. В новом коде удобнее методы Deferred — .done()/.fail()/.always(): их можно вызывать цепочкой уже после получения jqXHR, не запихивая всю логику в объект настроек, и они одинаково работают у $.ajax(), $.get(), $.post() и $.getJSON().

Как показать индикатор загрузки на время запроса?

Два варианта. Точечный — показать индикатор перед конкретным запросом и скрыть в колбэке .always(), который срабатывает и при успехе, и при ошибке. Глобальный — подписаться на события ajaxStart (показ индикатора) и ajaxStop (скрытие) через $(document).on(…): первый сработает, когда начнётся первый из одновременных запросов, второй — когда завершится последний, так что при нескольких параллельных запросах индикатор не мигнёт раньше времени.

[ наверх ]









 




Справочник по jQuery JavaScript API на русском языке