Перевод не завершен. Пожалуйста, помогите перевести эту статью с английского.

Это экспериментальная технология
Так как спецификация этой технологии ещё не стабилизировалась, смотрите таблицу совместимости по поводу использования в различных браузерах. Также заметьте, что синтаксис и поведение экспериментальной технологии может измениться в будущих версиях браузеров, вслед за изменениями спецификации.

Fetch API предоставляет интерфейс JavaScript для доступа и обработки частей протокола HTTP, таких как запросы и ответы. Оно также предоставляет глобальный метод fetch(), который даёт лёгкий, логический способ для извлечения ресурсов асинхронно по сети.

Такая функциональность была ранее достигнута с помощью XMLHttpRequest. Fetch представляет собой лучшую альтернативу, которая может быть легко использована другими технологиями, такими как Service Workers. Fetch также обеспечивает единое логическое место, чтобы определить другие связанные с HTTP понятия, такие как CORS и расширения для HTTP.

Обратите внимание, fetch спецификация отличается от jQuery.ajax() в основном двумя способами:

  • Promise возвращенный fetch() не отклонит состояние ошибки HTTP, даже если ответ HTTP 404 или 500.  Вместо этого, он будет выполнен нормально (с установкой статуса ok  в false) и будет отклонять только при сбое сети или если что-либо помешало запросу выполниться.
  • По умолчанию, fetch не будет отправлять или получать файлы cookie с сервера, в результате чего запросы будут без проверки подлинности, если сайт основан на сохранении сессии пользователя (для потправки cookies в опции init должны быть установлены параметры доступа).

Оформление запросов

Базовый запрос на получение действительно прост в настройке. Обратите внимание на следующий код:

var myImage = document.querySelector('img');

fetch('flowers.jpg').then(function(response) {
  return response.blob();
}).then(function(myBlob) {
  var objectURL = URL.createObjectURL(myBlob);
  myImage.src = objectURL;
});

Здесь мы забираем изображение по сети и вставляем его в <img> элемент. Самое простое использование fetch() принимает один аргумент — путь к ресурсу, который вы хотите получить — и возвращает promise, содержащее ответ (объект Response).

Конечно, это просто HTTP-ответ, а не фактическое изображение. Чтобы извлечь содержимое тела изображения из ответа, мы используем blob() метод  (определён на миксине Body, который включён в объектах Request и Response.)

Примечание: Миксин Body имеет подобные методы, чтобы извлечь другие типы body; см. Тело раздел подробнее.

Затем, из полученного Blob создаётся objectURL, который вставляется в img.

Fetch-запросы контролируются посредством директивы connect-src (Content Security Policy), а не директивой извлекаемых ресурсов.

Снабжение параметрами запроса

Метод fetch() может принимать второй параметр - обьект init, который позволяет вам контролировать различные настройки:

var myHeaders = new Headers();

var myInit = { method: 'GET',
               headers: myHeaders,
               mode: 'cors',
               cache: 'default' };

fetch('flowers.jpg', myInit).then(function(response) {
  return response.blob();
}).then(function(myBlob) {
  var objectURL = URL.createObjectURL(myBlob);
  myImage.src = objectURL;
});

Посмотрите описание fetch() со всеми доступными опциями и подробным описанием.

Отправка запроса с учётными данными

Чтобы браузеры могли отправлять запрос с учётными данными, добавьте credentials: 'include' в объект init, передаваемый вами в метод fetch():

fetch('https://example.com', {
  credentials: 'include'  
})

Напротив, чтобы быть уверенным, что учётные данные не передаются с запросом, используйте credentials: 'omit':

fetch('https://example.com', {
  credentials: 'omit'  
})

Проверка успешности выборки

В методе fetch() promise будет отклонён (reject) с TypeError, когда случится ошибка сети или не будет сконфигурирован CORS на стороне запрашиваемого сервера, хотя обычно это означает проблемы доступа или аналогичные — для примера, 404 не является сетевой ошибкой. Для достоверной проверки успешности fetch() будет включать проверку того, что promise успешен (resolved), затем проверку того, что  значение свойства Response.ok является true. Код будет выглядеть примерно так:

fetch('flowers.jpg').then(function(response) {
  if(response.ok) {
    return response.blob();
  }
  throw new Error('Network response was not ok.');
}).then(function(myBlob) { 
  var objectURL = URL.createObjectURL(myBlob); 
  myImage.src = objectURL; 
}).catch(function(error) {
  console.log('There has been a problem with your fetch operation: ' + error.message);
});

Составление своего объекта запроса

Вместо передачи пути ресурса, который вы хотите запросить вызовом fetch(), вы можете создать объект запроса, используя конструктор Request(), и передать его в fetch() аргументом:

var myHeaders = new Headers();

var myInit = { method: 'GET',
               headers: myHeaders,
               mode: 'cors',
               cache: 'default' };

var myRequest = new Request('flowers.jpg', myInit);

fetch(myRequest).then(function(response) {
  return response.blob();
}).then(function(myBlob) {
  var objectURL = URL.createObjectURL(myBlob);
  myImage.src = objectURL;
});

Конструктор Request() точно такие же параметры, как и метод fetch(). Вы даже можете передать существующий объект запроса для создания его копии:

var anotherRequest = new Request(myRequest, myInit);

Довольно удобно, когда тела запроса и ответа используются единожды (прим.пер.: "are one use only"). Создание копии как показано позволяет вам использовать запрос/ответ повторно, при изменении опций init, при желании. Копия должна быть сделана до прочтения тела, а чтение тела в копии также пометит его прочитанным в исходном запросе.

Примечание: Также есть метод clone(), создающий копии. Оба метода создания копии прекратят работу с ошибкой если тело оригинального запроса или ответа уже было прочитано, но чтение тела клонированного ответа или запроса не приведёт к маркировке оригинального.

Заголовки

Интерфейс Headers позволяет вам создать ваш собственный объект заголовков через конструктор Headers(). Объект заголовков - простая мультикарта имён-значений:

var content = "Hello World";
var myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Content-Length", content.length.toString());
myHeaders.append("X-Custom-Header", "ProcessThisImmediately");

То же может быть достигнуто путём передачи массива массивов или литерального объекта конструктору:

myHeaders = new Headers({
  "Content-Type": "text/plain",
  "Content-Length": content.length.toString(),
  "X-Custom-Header": "ProcessThisImmediately",
});

Содержимое может быть запрошено и извлечено:

console.log(myHeaders.has("Content-Type")); // true
console.log(myHeaders.has("Set-Cookie")); // false
myHeaders.set("Content-Type", "text/html");
myHeaders.append("X-Custom-Header", "AnotherValue");
 
console.log(myHeaders.get("Content-Length")); // 11
console.log(myHeaders.get("X-Custom-Header")); // ["ProcessThisImmediately", "AnotherValue"]
 
myHeaders.delete("X-Custom-Header");
console.log(myHeaders.get("X-Custom-Header")); // [ ]

Некоторые из этих операций могут быть использованы только в ServiceWorkers, но они предоставляют более удобный API для манипуляции заголовками.

Все методы Headers выбрасывают TypeError, если имя используемого заголовка не является валидным именем HTTP Header. Операции мутации выбросят TypeError если есть защита от мутации (смотрите ниже) (прим.пер.: "if there is an immutable guard"). В противном случае они прерываются молча. Например:

var myResponse = Response.error();
try {
  myResponse.headers.set("Origin", "http://mybank.com");
} catch(e) {
  console.log("Cannot pretend to be a bank!");
}

Хорошим вариантом использования заголовков  является проверка корректности типа контента перед его обработкой. Например:

fetch(myRequest).then(function(response) {
    var contentType = response.headers.get("content-type");
    if(contentType && contentType.includes("application/json")) {
      return response.json();
    }
    throw new TypeError("Oops, we haven't got JSON!");
  })
  .then(function(json) { /* process your JSON further */ })
  .catch(function(error) { console.log(error); });

Защита

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

Возможные значения:

  • none: по умолчанию.
  • request: защита объекта заголовков, полученного по запросу (Request.headers).
  • request-no-cors: защита объекта заголовков, полученного по запросу созданного с Request.mode no-cors.
  • response: защита Headers полученных от ответа (Response.headers).
  • immutable: в основном, используется в ServiceWorkers; делает объект заголовков read-only.

Примечание: Вы не можете добавить или установить request защищаемые Headers’ заголовок Content-Length. Аналогично, вставка Set-Cookie в заголовок ответа недопустимо: ServiceWorkers не допускают установки cookies через синтезированные ответы.

Объекты ответов

Как вы видели выше, экземпляр Response будет возвращен когда fetch() промис будет исполнен.

Свойства объекта-ответа которые чаще всего используются:

  • Response.status — Целочисленное (по умолчанию 200) содержит код статуса ответа.
  • Response.statusText — Строка (по умолчанию"OK"), которая соответствует HTTP коду статуса.
  • Response.ok — как сказано ранее, это короткое свойство для упрощения проверки на то что статус ответа находится гдето между 200-299 включительно. Это свойство типа Boolean.

They can also be created programmatically via JavaScript, but this is only really useful in ServiceWorkers, when you are providing a custom response to a received request using a respondWith() method:

var myBody = new Blob();

addEventListener('fetch', function(event) { // ServiceWorker intercepting a fetch
  event.respondWith(
    new Response(myBody, {
      headers: { "Content-Type" : "text/plain" }
    })
  );
});

The Response() constructor takes two optional arguments — a body for the response, and an init object (similar to the one that Request() accepts.)

Note: The static method error() simply returns an error response. Similarly, redirect() returns a response resulting in a redirect to a specified URL. These are also only relevant to Service Workers.

Тело

Both requests and responses may contain body data. A body is an instance of any of the following types:

The Body mixin defines the following methods to extract a body (implemented by both Request and Response). These all return a promise that is eventually resolved with the actual content.

This makes usage of non-textual data much easier than it was with XHR.

Request bodies can be set by passing body parameters:

var form = new FormData(document.getElementById('login-form'));
fetch("/login", {
  method: "POST",
  body: form
});

Both request and response (and by extension the fetch() function), will try to intelligently determine the content type. A request will also automatically set a Content-Type header if none is set in the dictionary.

Функция обнаружения

Fetch API support can be detected by checking for the existence of Headers, Request, Response or fetch() on the Window or Worker scope. For example:

if (self.fetch) {
    // run my fetch request here
} else {
    // do something with XMLHttpRequest?
}

Полифилл

Чтобы использовать Fetch в неподдерживаемых браузерах, имеется  Fetch Polyfill , который воссоздает функциональность для не поддерживающих браузеров.

Спецификации

Спецификации Статус Комментарий
Fetch Живой стандарт Initial definition

Совместимость браузера

We're converting our compatibility data into a machine-readable JSON format. This compatibility table still uses the old format, because we haven't yet converted the data it contains. Find out how you can help!

Feature Chrome Edge Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
Базовая поддержка 42 14 39 (39)
34 (34)[1]
52 (52)[2]
Нет 29
28[1]
10.1
Feature Android Webview Chrome for Android Firefox Mobile (Gecko) IE Phone Opera Mobile Safari Mobile Chrome for Android
Базовая поддержка 42 42 (Да) Нет ? 10.1 ?

[1] This API is implemented behind a preference.

[2] Prior to Firefox 52, get() only returned the first value in the specified header, with getAll() returning all values. From 52 onwards, get() now returns all values and getAll() has been deleted.

См. также

Метки документа и участники

 Внесли вклад в эту страницу: moskitos80, InoY, Bargamut, zhvirblis, Scion, bad4iz
 Обновлялась последний раз: moskitos80,