Перейти к основному содержимому

CORS

Есть два вида запросов на другой источник:

  1. Простые.
  2. Все остальные.

Простой запрос – это запрос, удовлетворяющий следующим условиям:

  1. Простой метод: GET, POST или HEAD
  2. Простые заголовки – разрешены только:
    • Accept,
    • Accept-Language,
    • Content-Language,
    • Content-Type со значением application/x-www-form-urlencodedmultipart/form-data или text/plain. (работает в обе стороны и на отправку и на получение)

Принципиальное отличие между ними состоит в том, что «простой запрос» может быть сделан через <form> или <script>, без каких-то специальных методов.

Когда мы пытаемся сделать непростой запрос, браузер посылает специальный предварительный запрос («preflight»), который спрашивает у сервера – согласен ли он принять такой непростой запрос или нет?

CORS для простых запросов

При запросе на другой источник браузер всегда ставит сам заголовок Origin.

Сервер может проверить Origin и, если он согласен принять такой запрос, добавить особый заголовок Access-Control-Allow-Origin к ответу. Этот заголовок должен содержать разрешённый источник (в нашем случае https://javascript.info) или звёздочку *. Тогда ответ успешен, в противном случае возникает ошибка.

Здесь браузер играет роль доверенного посредника:

  1. Он гарантирует, что к запросу на другой источник добавляется правильный заголовок Origin.
  2. Он проверяет наличие разрешающего заголовка Access-Control-Allow-Origin в ответе и, если всё хорошо, то JavaScript получает доступ к ответу сервера, в противном случае – доступ запрещается с ошибкой.

По умолчанию при запросе к другому источнику JavaScript может получить доступ только к так называемым «простым» заголовкам ответа:

  • Cache-Control
  • Content-Language
  • Content-Length
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

Чтобы разрешить JavaScript доступ к любому другому заголовку ответа, сервер должен указать заголовок Access-Control-Expose-Headers.

«Непростые» запросы

Браузер не делает «непростые» запросы (которые нельзя было сделать в прошлом) сразу. Перед этим он посылает предварительный запрос, спрашивая разрешения.

Предварительный запрос использует метод OPTIONS, у него нет тела, но есть три заголовка:

  • Origin содержит именно источник (домен/протокол/порт), без пути.
  • Access-Control-Request-Method содержит HTTP-метод «непростого» запроса.
  • Access-Control-Request-Headers предоставляет разделённый запятыми список его «непростых» HTTP-заголовков.

Если сервер согласен принимать такие запросы, то он должен ответить без тела, со статусом 200 и с заголовками:

  • Access-Control-Allow-Origin должен содержать разрешённый источник.
  • Access-Control-Allow-Methods должен содержать разрешённые методы.
  • Access-Control-Allow-Headers должен содержать список разрешённых заголовков.
  • Кроме того, заголовок Access-Control-Max-Age может указывать количество секунд, на которое нужно кешировать разрешения.

Предзапрос осуществляется «за кулисами», невидимо для JavaScript.

JavaScript получает только ответ на основной запрос или ошибку, если со стороны сервера нет разрешения.

Авторизационные данные

Запрос на другой источник по умолчанию не содержит авторизационных данных (credentials), под которыми здесь понимаются куки и заголовки HTTP-аутентификации. Чтобы включить отправку авторизационных данных в fetch, нам нужно добавить опцию credentials: "include".

Если сервер согласен принять запрос с авторизационными данными, он должен добавить заголовок Access-Control-Allow-Credentials: true к ответу, в дополнение к Access-Control-Allow-Origin.

Обратите внимание: в Access-Control-Allow-Origin запрещено использовать звёздочку * для запросов с авторизационными данными. Там должен быть именно источник.

CORS and <img />

Атрибут crossorigin является частью технологии CORS и применяется при загрузке изображения со стороннего сайта для использования в элементе <canvas>.

Если у элемента <img> не указан атрибут crossorigin, то посылается запрос, не относящийся к CORS (без заголовка Origin). При этом браузер помечает изображение как испорченное (оно не считается безопасным) и ограничивает доступ к его данным, не позволяя использовать изображение в элементах <canvas>.

Если атрибут crossorigin указан, то посылается CORS-запрос (с заголовком Origin). Если сервер не соглашается разрешить сторонний доступ, то браузер блокирует загрузку изображения и фиксирует ошибку в панели разработчика.