На данный момент мы уже многое знаем про fetch
.
Давайте рассмотрим оставшуюся часть API, чтобы охватить все возможности.
Заметим: большинство этих возможностей используются редко. Вы можете пропустить эту главу и, несмотря на это, нормально использовать fetch
.
Тем не менее, полезно знать, что вообще может fetch
, чтобы, когда появится необходимость, вернуться и прочитать конкретные детали.
Нижеследующий список – это все возможные опции для fetch
с соответствующими значениями по умолчанию (в комментариях указаны альтернативные значения):
let promise = fetch(url, {
method: "GET", // POST, PUT, DELETE, etc.
headers: {
// значение этого заголовка обычно ставится автоматически,
// в зависимости от тела запроса
"Content-Type": "text/plain;charset=UTF-8"
},
body: undefined, // string, FormData, Blob, BufferSource или URLSearchParams
referrer: "about:client", // или "" для того, чтобы не послать заголовок Referer,
// или URL с текущего источника
referrerPolicy: "strict-origin-when-cross-origin", // no-referrer-when-downgrade, no-referrer, origin, same-origin...
mode: "cors", // same-origin, no-cors
credentials: "same-origin", // omit, include
cache: "default", // no-store, reload, no-cache, force-cache или only-if-cached
redirect: "follow", // manual, error
integrity: "", // контрольная сумма, например "sha256-abcdef1234567890"
keepalive: false, // true
signal: undefined, // AbortController, чтобы прервать запрос
window: window // null
});
Довольно-таки внушительный список, не так ли?
В главе Fetch мы разобрали параметры method
, headers
и body
.
Опция signal
разъяснена в главе в Fetch: прерывание запроса.
Теперь давайте пройдёмся по оставшимся возможностям.
referrer, referrerPolicy
Данные опции определяют, как fetch
устанавливает HTTP-заголовок Referer
.
Обычно этот заголовок ставится автоматически и содержит URL-адрес страницы, с которой пришёл запрос. В большинстве случаев он совсем неважен, в некоторых случаях, с целью большей безопасности, имеет смысл убрать или укоротить его.
Опция referrer
позволяет установить любой Referer
в пределах текущего источника или же убрать его.
Чтобы не отправлять Referer
, нужно указать значением пустую строку:
fetch('/page', {
referrer: "" // не ставить заголовок Referer
});
Для того, чтобы установить другой URL-адрес (должен быть с текущего источника):
fetch('/page', {
// предположим, что мы находимся на странице https://javascript.info
// мы можем установить любое значение Referer при условии, что оно принадлежит текущему источнику
referrer: "https://javascript.info/anotherpage"
});
Опция referrerPolicy
устанавливает общие правила для Referer
.
Выделяется 3 типа запросов:
- Запрос на тот же источник.
- Запрос на другой источник.
- Запрос с HTTPS to HTTP (с безопасного протокола на небезопасный).
В отличие от настройки referrer
, которая позволяет задать точное значение Referer
, настройка referrerPolicy
сообщает браузеру общие правила, что делать для каждого типа запроса.
Возможные значения описаны в спецификации Referrer Policy:
"strict-origin-when-cross-origin"
– значение по умолчанию: для"same-origin"
отправлять полныйReferer
, для"cross-origin"
отправлять только"origin"
, если только это не HTTPS→HTTP запрос, тогда не отправлять ничего."no-referrer-when-downgrade"
– всегда отправлять полныйReferer
, за исключением случаев, когда мы отправляем запрос с HTTPS на HTTP (на менее безопасный протокол)."no-referrer"
– никогда не отправлятьReferer
."origin"
– отправлять вReferer
только текущий источник, а не полный URL-адрес страницы, например, посылать толькоhttp://site.com
вместоhttp://site.com/path
."origin-when-cross-origin"
– отправлять полныйReferer
для запросов в пределах текущего источника, но для запросов на другой источник отправлять только сам источник (как выше)."same-origin"
– отправлять полныйReferer
для запросов в пределах текущего источника, а для запросов на другой источник не отправлять его вообще."strict-origin"
– отправлять только значение источника, не отправлятьReferer
для HTTPS→HTTP запросов."unsafe-url"
– всегда отправлять полный URL-адрес вReferer
, даже при запросахHTTPS→HTTP
.
Вот таблица со всеми комбинациями:
Значение | На тот же источник | На другой источник | HTTPS→HTTP |
---|---|---|---|
"no-referrer" |
- | - | - |
"no-referrer-when-downgrade" |
full | full | - |
"origin" |
origin | origin | origin |
"origin-when-cross-origin" |
full | origin | origin |
"same-origin" |
full | - | - |
"strict-origin" |
origin | origin | - |
"strict-origin-when-cross-origin" или "" (по умолчанию) |
full | origin | - |
"unsafe-url" |
full | full | full |
Допустим, у нас есть админка со структурой URL, которая не должна стать известной снаружи сайта.
Если мы отправляем запрос fetch
, то по умолчанию он всегда отправляет заголовок Referer
с полным URL-адресом нашей админки (исключение – это когда мы делаем запрос от HTTPS в HTTP, в таком случае Referer
не будет отправляться).
Например, Referer: https://javascript.info/admin/secret/paths
.
Если мы хотим, чтобы другие сайты получали только источник, но не URL-путь, это сделает такая настройка:
fetch('https://another.com/page', {
// ...
referrerPolicy: "origin-when-cross-origin" // Referer: https://javascript.info
});
Мы можем поставить её во все вызовы fetch
, возможно, интегрировать в JavaScript-библиотеку нашего проекта, которая делает все запросы и внутри использует fetch
.
Единственным отличием в поведении будет то, что для всех запросов на другой источник fetch
будет посылать только источник в заголовке Referer
(например, https://javascript.info
, без пути). А для запросов на наш источник мы продолжим получать полный Referer
(это может быть полезно для отладки).
fetch
Политика установки Referer, описанная в спецификации Referrer Policy, существует не только для fetch
, она более глобальная.
В частности, можно поставить политику по умолчанию для всей страницы, используя HTTP-заголовок Referrer-Policy
, или на уровне ссылки <a rel="noreferrer">
.
mode
Опция mode
– это защита от нечаянной отправки запроса на другой источник:
"cors"
– стоит по умолчанию, позволяет делать такие запросы так, как описано в Fetch: запросы на другие сайты,"same-origin"
– запросы на другой источник запрещены,"no-cors"
– разрешены только простые запросы на другой источник.
Эта опция может пригодиться, если URL-адрес для fetch
приходит от третьей стороны, и нам нужен своего рода «глобальный выключатель» для запросов на другие источники.
credentials
Опция credentials
указывает, должен ли fetch
отправлять куки и авторизационные заголовки HTTP вместе с запросом.
"same-origin"
– стоит по умолчанию, не отправлять для запросов на другой источник,"include"
– отправлять всегда, но при этом необходим заголовокAccess-Control-Allow-Credentials
в ответе от сервера, чтобы JavaScript получил доступ к ответу сервера, об этом говорилось в главе Fetch: запросы на другие сайты,"omit"
– не отправлять ни при каких обстоятельствах, даже для запросов, сделанных в пределах текущего источника.
cache
По умолчанию fetch
делает запросы, используя стандартное HTTP-кеширование. То есть, учитывается заголовки Expires
, Cache-Control
, отправляется If-Modified-Since
и так далее. Так же, как и обычные HTTP-запросы.
Настройка cache
позволяет игнорировать HTTP-кеш или же настроить его использование:
"default"
–fetch
будет использовать стандартные правила и заголовки HTTP кеширования,"no-store"
– полностью игнорировать HTTP-кеш, этот режим становится режимом по умолчанию, если присутствуют такие заголовки какIf-Modified-Since
,If-None-Match
,If-Unmodified-Since
,If-Match
, илиIf-Range
,"reload"
– не брать результат из HTTP-кеша (даже при его присутствии), но сохранить ответ в кеше (если это дозволено заголовками ответа);"no-cache"
– в случае, если существует кешированный ответ – создать условный запрос, в противном же случае – обычный запрос. Сохранить ответ в HTTP-кеше,"force-cache"
– использовать ответ из HTTP-кеша, даже если он устаревший. Если же ответ в HTTP-кеше отсутствует, сделать обычный HTTP-запрос, действовать как обычно,"only-if-cached"
– использовать ответ из HTTP-кеша, даже если он устаревший. Если же ответ в HTTP-кеше отсутствует, то выдаётся ошибка. Это работает, только когдаmode
установлен в"same-origin"
.
redirect
Обычно fetch
прозрачно следует HTTP-редиректам, таким как 301, 302 и так далее.
Это можно поменять при помощи опции redirect
:
"follow"
– стоит по умолчанию, следовать HTTP-редиректам,"error"
– ошибка в случае HTTP-редиректа,"manual"
– не следовать HTTP-редиректу, но установить адрес редиректа вresponse.url
, аresponse.redirected
будет иметь значениеfalse
, чтобы мы могли сделать перенаправление на новый адрес вручную.
integrity
Опция integrity
позволяет проверить, соответствует ли ответ известной заранее контрольной сумме.
Как описано в спецификации, поддерживаемыми хеш-функциями являются SHA-256, SHA-384 и SHA-512. В зависимости от браузера, могут быть и другие.
Например, мы скачиваем файл, и мы точно знаем, что его контрольная сумма по алгоритму SHA-256 равна «abcdef» (разумеется, настоящая контрольная сумма будет длиннее).
Мы можем добавить это в настройку integrity
вот так:
fetch('http://site.com/file', {
integrity: 'sha256-abcdef'
});
Затем fetch
самостоятельно вычислит SHA-256 и сравнит его с нашей строкой. В случае несоответствия будет ошибка.
keepalive
Опция keepalive
указывает на то, что запрос может «пережить» страницу, которая его отправила.
Например, мы собираем статистические данные о том, как посетитель ведёт себя на нашей странице (на что он кликает, части страницы, которые он просматривает), для анализа и улучшения интерфейса.
Когда посетитель покидает нашу страницу – мы хотим сохранить собранные данные на нашем сервере.
Для этого мы можем использовать событие window.onunload
:
window.onunload = function() {
fetch('/analytics', {
method: 'POST',
body: "statistics",
keepalive: true
});
};
Обычно, когда документ выгружается, все связанные с ним сетевые запросы прерываются. Но настройка keepalive
указывает браузеру выполнять запрос в фоновом режиме даже после того, как пользователь покидает страницу. Поэтому эта опция обязательна, чтобы такой запрос удался.
У неё есть ряд ограничений:
- Мы не можем посылать мегабайты: лимит тела для запроса с
keepalive
– 64кб.- Если мы собираем больше данных, можем отправлять их регулярно, «пакетами», тогда на момент последнего запроса в
onunload
их останется немного. - Этот лимит распространяется на все запросы с
keepalive
. То есть, мы не можем его обойти, послав 100 запросов одновременно – каждый по 64Кбайт.
- Если мы собираем больше данных, можем отправлять их регулярно, «пакетами», тогда на момент последнего запроса в
- Мы не сможем обработать ответ от сервера, если запрос сделан при
onunload
: в тот момент документ уже выгружен, его функции не сработают.- Обычно сервер посылает пустой ответ на такие запросы, так что это не является проблемой.