Перевод: сумасшедший технический ботаник
предисловие
CORS и файлы cookie — очень важная проблема во внешнем интерфейсе, но в большинстве случаев, поскольку домены внешнего и внутреннего интерфейса обычно одинаковы, эти проблемы возникают редко. Или просто запросите настройки бэкэндаAccess-Control-Allow-Origin: *
Вот и все, совсем немного, чтобы понять механизм операции.
для этой проблемы,MDNПо вышесказанному есть очень подробные пояснения, поэтому данная статья в основном посвящена разбору ключевых моментов и проблем, которые часто возникают в реальной эксплуатации.
Политика того же происхождения
Чтобы предотвратить бурное распространение javascript на веб-страницах, политика одного и того же происхождения предусматривает определенные ресурсы, и код должен быть вгомологияможно получить только доступ.
Что такое гомология? одна порцияdocument
источник, определяемый протоколом, хостом и портом. То есть, если файл 1 исходит изhttp://kalan.com
, а файл 2 взят изhttps://kalan.com
Они не гомологичны. А если это субдомен? подобноhttps://api.foobar.com
а такжеhttps://app.foobar.com
. Поскольку их хосты разные, они не являются одним и тем же источником.
И некоторые ресурсы по своей природе доступны через перекрестное происхождение:
<img />
-
<video />
,<audio />
-
<iframe />
: Вы можете помешать другим встраиваться, определяя заголовок - пройти через
<link rel="stylesheet" href />
Загруженный CSS-скрипт -
<script src="" />
Загруженный Javascript
Запросы между источниками, сделанные с помощью кода, ограничиваются политикой одного и того же источника (например, Fetch, XHR).
Очевидно, что это правило слишком строгое. Если он будет ограничен политикой одного и того же происхождения, разработка интерфейсных и серверных компонентов будет затруднена, и не будет возможности применить API других SDK в качестве XHR. Поэтому появился механизм CORS (Cross-Origin Resource Sharing).
CORS (обмен ресурсами между источниками)
Многие думают, что CORS — это знания, которыми должен обладать только интерфейс. Однако CORS обычно требует, чтобы серверная часть устанавливала соответствующие заголовки HTTP и понимала их значение для правильной работы.
Так как же работают кросс-доменные запросы?
В основном используется для относительного контроля доступа двумя заголовками: в запросеOrigin
и в ответAccess-Control-Allow-Origin
.
Просто отправьте запрос в заголовках Origin и responseAccess-Control-Allow-Origin
то же значение илиAccess-Control-Allow-Origin: *
(это означает, что любому домену разрешен доступ к ресурсам), в настоящее время ограничения на CORS будут ослаблены, что позволит получить доступ к междоменным ресурсам.
Если политика CORS не соблюдается, будет отображаться следующее сообщение:
Вы также получите предупреждение, если попытаетесь прочитать возвращаемый объект.
Во-первых, если мы будем следовать подсказкам и изменим режим выборки наno-cors
Что случится? Это правда, что мы избавились от раздражающих сообщений об ошибках, но, похоже, ситуация не улучшается.
no-cors
Это не панацея, даже если вы используете этот паттерн, CORS не откроет из-за этого дверь, то есть ваш запрос не будет успешно отправлен. Он также появилсяSyntaxError: Unexpected end of input
эта ошибка. Этот шаблон обычно используется в сочетании с Service Workers.
Из приведенного выше эксперимента видно, чтоЕсть только один трюк, чтобы снять печать CORS, это добавить правильныйControl-Access-Allow-Origin
(хост должен быть таким же, как исходный или*
).
Кроме того, механизм CORS работает только тогда, когда javascript отправляет XHR или fetch.Как правило, curl или postman не имеют этого механизма, поэтому он часто игнорируется при тестировании конечных точек API, что приводит к расхождениям между интерфейсом и сервером, когда тестирование API.
Некоторые запросы cross-origin не проходят предварительную проверку, а некоторые — делают, на MDN четко написано:
- Должен быть одним из GET, HEAD, POST
- Не содержит заголовков, кроме автоматически установленных пользовательским агентом и определенных заголовков. приемлемоheader
- если есть
Content-Type
(обратите внимание на заголовок запроса,не заголовок ответа), оно должно быть одним из следующих значений:application/x-www-form-encoded
,text/plain
,multipart/form-data
То есть, если вышеуказанные условия не выполняются, будет выдан предварительный запрос.
мы пытаемся поставитьContent-Type
изменить наapplication/json
проверить это (не могуapplication/x-www-form-encoded
,text/plain
,multipart/form-data
).
Preflight
Так называемая предварительная проверка заключается в том, что запрос сначала будет использовать метод HTTP OPTION, чтобы постучать в дверь другого домена, а настоящий запрос будет отправлен только после подтверждения отсутствия проблемы. Как только это условие срабатывает, все становится намного более громоздким.
- Необходимо присоединиться к OPTIONS одной и той же конечной точке API,И установите Access-Control-Allow-Origin для соответствия условиям CORS.
- должен присоединиться
Access-Control-Allow-Headers
, и должен содержатьвсеЗаголовок не входит в условие, иначе оно не пройдет.
Если предпечатная проверка не пройдена, сообщение об ошибке будет следующего вида:
Access to fetch at 'http://localhost:3001/trigger-preflight' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.
или ты не тамOPTIONS
добавить в заголовок ответаAccess-Control-Allow-Origin
:
Access to fetch at 'http://localhost:3001/trigger-preflight' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
В случае успеха вы увидите два запроса в сети, один OPTIONS, а другой реальный запрос.
Картинка выше ВАРИАНТ, картинка ниже ПОЛУЧИТЬ
Что, если мы добавим самодельный заголовок? В соответствии с условиями, определенными MDN, предварительный запрос также должен быть запущен.X-Access-Token
Посмотрите, что происходит.
Пройти предполетную проверку действительно невозможно.Если хотите пройти, то должны поставитьX-Access-Token
ПрисоединяйсяAccess-Control-Allow-Headers
середина.
запрос с аутентификацией
Файлы cookie не могут передаваться между доменами, а это означает, что файлы cookie из разных источников не могут передаваться и получать доступ друг к другу, иначе мир погрузится в хаос.
Однако, если вы отправляете запрос в домен b в домене a, а домен b возвращает информацию о файлах cookie, то файл cookie будет храниться в домене a в виде домена b, если он не установленwithCredentials
илиcredentials: ‘include’
Если да, то даже если сервер вернетсяSet-Cookie
, то же не будет написано. Как показано ниже:
Сервер возвращает Set-Cookie
не пишется в браузере
В обычных условиях, если снова используется API домена b, файл cookie не будет автоматически отправлен. В этом случае вы должныXHR
настраиватьwithCredentials
илиfetch
установить в опциях{ credentials: 'include' }
, так как это тоже междоменный запрос, он тоже должен быть присоединен согласно условиям CORSAccess-Control-Allow-Origin
Во избежание проблем с безопасностью браузеры также имеют правилаAccess-Control-Allow-Origin
не может быть*
.
Access to fetch at 'http://localhost:3001/cookie' from origin 'http://localhost:3000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
Но этого недостаточно, браузер автоматически не отклонитAccess-Control-Allow-Credentials
ответ, поэтому, если вы хотите передать идентификационную информацию на междоменный сервер, вы должны добавить дополнительныйAccess-Control-Allow-Credentials: true
. Если они установлены успешно, это должно выглядеть так, как показано на рисунке ниже.В Request Cookie вы можете увидеть, что cookie был успешно отправлен.
В Request Cookies есть гнездо!
Что ж, если вы успешно настроили эти вещи, все еще возможно, что нет никакого способа получить cookie на сервер. Это могут быть следующие ситуации:
1. Пользователь отключил файлы cookie для этого домена.
Возможно, пользователь добавил вас в черный список, поэтому cookie не может быть успешно отправлен
Решение:
- изменить домен
Проверьте, почему вы заблокированы пользователями
2. Пользователь блокирует файлы cookie со всех внешних веб-сайтов.
Параметр «Блокировать все файлы cookie» иногда включается в Safari, что может причинить вам много боли при отладке.
постскриптум
Неблагодарное дело иметь дело с CORS, особенно иногда забывая добавить его перед запуском CI/CDAccess-Control-Allow-Origin
илиAccess-Control-Allow-Credentials
, то развертывание может занять еще один день. На этот раз я разобрался с некоторыми распространенными проблемами, надеюсь, что если возникнет подобная ситуация в будущем, я смогу знать, как с ней справиться.
Наконец прикрепленисходный код.