На данный момент мы уже многое знаем про 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
});Довольно-таки внушительный список, не так ли?
В главе info:fetch мы разобрали параметры method, headers и body.
Опция signal разъяснена в главе в info:fetch-abort.
Теперь давайте пройдёмся по оставшимся возможностям.
Данные опции определяют, как 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 (это может быть полезно для отладки).
```smart header="Политика установки Referer (Referrer Policy) - не только для fetch"
Политика установки Referer, описанная в спецификации Referrer Policy, существует не только для `fetch`, она более глобальная.
В частности, можно поставить политику по умолчанию для всей страницы, используя HTTP-заголовок Referrer-Policy, или на уровне ссылки <a rel="noreferrer">.
## mode
Опция `mode` - это защита от нечаянной отправки запроса на другой источник:
- **`"cors"`** -- стоит по умолчанию, позволяет делать такие запросы так, как описано в <info:fetch-crossorigin>,
- **`"same-origin"`** -- запросы на другой источник запрещены,
- **`"no-cors"`** -- разрешены только простые запросы на другой источник.
Эта опция может пригодиться, если URL-адрес для `fetch` приходит от третьей стороны, и нам нужен своего рода "глобальный выключатель" для запросов на другие источники.
## credentials
Опция `credentials` указывает, должен ли `fetch` отправлять куки и авторизационные заголовки HTTP вместе с запросом.
- **`"same-origin"`** -- стоит по умолчанию, не отправлять для запросов на другой источник,
- **`"include"`** -- отправлять всегда, но при этом необходим заголовок `Access-Control-Allow-Credentials` в ответе от сервера, чтобы JavaScript получил доступ к ответу сервера, об этом говорилось в главе <info:fetch-crossorigin>,
- **`"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` позволяет проверить, соответствует ли ответ известной заранее контрольной сумме.
Как описано в [спецификации](https://w3c.github.io/webappsec-subresource-integrity/), поддерживаемыми хеш-функциями являются SHA-256, SHA-384 и SHA-512. В зависимости от браузера, могут быть и другие.
Например, мы скачиваем файл, и мы точно знаем, что его контрольная сумма по алгоритму SHA-256 равна "abcdef" (разумеется, настоящая контрольная сумма будет длиннее).
Мы можем добавить это в настройку `integrity` вот так:
```js
fetch('http://site.com/file', {
integrity: 'sha256-abcdef'
});
Затем fetch самостоятельно вычислит SHA-256 и сравнит его с нашей строкой. В случае несоответствия будет ошибка.
Опция keepalive указывает на то, что запрос может "пережить" страницу, которая его отправила.
Например, мы собираем статистические данные о том, как посетитель ведёт себя на нашей странице (на что он кликает, части страницы, которые он просматривает), для анализа и улучшения интерфейса.
Когда посетитель покидает нашу страницу - мы хотим сохранить собранные данные на нашем сервере.
Для этого мы можем использовать событие unload на объекте window:
window.onunload = function() {
fetch('/analytics', {
method: 'POST',
body: "statistics",
*!*
keepalive: true
*/!*
});
};Обычно, когда документ выгружается, все связанные с ним сетевые запросы прерываются. Но настройка keepalive указывает браузеру выполнять запрос в фоновом режиме даже после того, как пользователь покидает страницу. Поэтому эта опция обязательна, чтобы такой запрос удался.
У неё есть ряд ограничений:
- Мы не можем посылать мегабайты: лимит тела для запроса с
keepalive- 64кб.- Если мы собираем больше данных, можем отправлять их регулярно, "пакетами", тогда на момент события
unloadих останется немного. - Этот лимит распространяется на все запросы с
keepalive. То есть мы не можем его обойти, послав 100 запросов одновременно - каждый по 64Кбайт.
- Если мы собираем больше данных, можем отправлять их регулярно, "пакетами", тогда на момент события
- Мы не можем обработать ответ сервера, если документ выгружен. Поэтому в нашем примере
fetchзавершится успешно благодаряkeepalive, но последующие функции не сработают.- В большинстве случаев, например, при отправке статистики, это не проблема, поскольку сервер просто принимает данные и обычно отправляет пустой ответ на такие запросы.