Когда вы сталкиваетесь с междоменной проблемой, не сразу копируйте ее и пробуйте. Пожалуйста, внимательно прочитайте эту статью перед обработкой. Я верю, что это может помочь вам.
Подготовка перед анализом:
Адрес внешнего веб-сайта: http://localhost:8080.
URL-адрес сервера: http://localhost:59200.
Во-первых, убедитесь, что сервер не обрабатывает междоменные проблемы. Во-вторых, используйте почтальона, чтобы проверить, нормально ли работает интерфейс сервера.
Когда веб-сайт 8080 обращается к интерфейсу сервера, возникает междоменная проблема. Как ее решить? Далее я перечислил различные ситуации, возникающие в разных доменах, и решил их через прокси-сервер nginx (то же самое происходит и в фоновом режиме, если вы понимаете принцип).
Междоменный подход в основном включает в себя 4 заголовка ответа:
Во многих статьях в Интернете говорится, что добавление этих заголовков ответов непосредственно в Nginx может решить междоменные проблемы. Конечно, большинство случаев можно решить, но я считаю, что есть еще много случаев, когда о междоменных проблемах все равно будут сообщать. конфигурация правильная.
Что такое предполетный запрос?:когда произойдет Междоменный доменусловное время,Браузер сначала запрашивает сервер,Находится ли доменное имя текущей веб-страницы в списке разрешений сервера.,И какие HTTP-глаголы и поля заголовка можно использовать. получить только положительный ответ,Браузер выдаст формальный запрос XMLHttpRequest.,В противном случае будет сообщено об ошибке. Как показано ниже
Приступаем к симуляции:
Порт прокси Nginx: 22222, конфигурация следующая
server {
listen 22222;
server_name localhost;
location / {
proxy_pass http://localhost:59200;
}
}
Проверьте, успешно ли работает прокси, и снова получите доступ к интерфейсу через порт прокси-сервера Nginx 2222. Вы можете видеть, что доступ к интерфейсу возможен в обычном режиме после передачи прокси, как показано ниже.
Затем используйте веб-сайт 8080 для доступа к адресу интерфейса прокси-сервера Nginx. Сообщение об ошибке выглядит следующим образом: ↓↓↓.
Случай 1:
“ Access to XMLHttpRequest at ‘http://localhost:22222/api/Login/TestGet’ from origin ‘http://localhost:8080’ 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.
Ошибку можно четко определить по сообщению об ошибке (обратите внимание на красную часть). Описание priflight — это предварительный запрос. Междоменный механизм CORS сначала выполнит предполетный запрос (запрос OPTIONS), а затем реальный запрос. быть отправлено после успешного выполнения запроса. Это сделано для того, чтобы серверы знали о стандарте CORS и защищали старые серверы, которые не поддерживают CORS.
Из сообщения об ошибке мы можем обнаружить, что в заголовке ответа на предварительный запрос отсутствует Access-Control-Allow-Origin. Мы можем просто изменить его, если он неправильный. Измените информацию о конфигурации Nginx следующим образом (красная часть — добавленная часть), заполните все недостающее, это очень просто и понятно.
server {
listen 22222;
server_name localhost;
location / {
add_header Access-Control-Allow-Origin 'http://localhost:8080';
proxy_pass http://localhost:59200;
}
}
Ха-ха, когда я был полон радости и думал, что смогу решить эту проблему, я обнаружил, что все еще сообщаю о той же проблеме.
Однако в нашей конфигурации все в порядке. Проблема связана с Nginx. Ссылка ниже: http://nginx.org/en/docs/http/ngx_http_headers_module.html.
Директива add_header используется для добавления поля возвращаемого заголовка, которое действительно тогда и только тогда, когда коды состояния соответствуют указанным на рисунке. Если вы хотите, чтобы каждое ответное сообщение содержало информацию о поле заголовка, вам необходимо добавить всегда в конце (после моего тестирования только информацию заголовка Access-Control-Allow-Origin необходимо добавлять с помощью Always, а другая информация заголовка будет переносим обратно без добавления всегда), тогда попробуем
server {
listen 22222;
server_name localhost;
location / {
add_header Access-Control-Allow-Origin 'http://localhost:8080' always;
proxy_pass http://localhost:59200;
}
}
После изменения конфигурации я обнаружил, что она вступила в силу. Конечно, это не междоменная проблема. Вышеупомянутая проблема была решена, поскольку содержание ошибки изменилось.
Случай 2:
“ Access to XMLHttpRequest at ‘http://localhost:22222/api/Login/TestGet’ from origin ‘http://localhost:8080’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.
Из сообщения об ошибке можно узнать, что предварительный запрос (запрос опции), который является поведением междоменного браузера по умолчанию, не получает код состояния ok. В это время файл конфигурации изменяется при запросе. запрос опции, код состояния возвращается в браузер (обычно 204).
server {
listen 22222;
server_name localhost;
location / {
add_header Access-Control-Allow-Origin 'http://localhost:8080' always;
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_pass http://localhost:59200;
}
}
После завершения настройки я обнаружил, что сообщение об ошибке изменилось.
Случай 3:
“ Access to XMLHttpRequest at ‘http://localhost:22222/api/Login/TestGet’ from origin ‘http://localhost:8080’ has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.
Это означает, что авторизация информации заголовка отсутствует в заголовке ответа предварительного запроса Access-Control-Allow-Headers (различные ситуации будут разными. После возникновения междоменного доступа добавленная информация пользовательского заголовка не разрешена, и ее необходимо добавить в заголовок ответа на запрос. Контроль доступа. -Allow-Headers, чтобы браузер знал, что перенос этой информации заголовка распознается сервером как законный. Здесь я несу авторизацию, а остальные могут быть токенами. Я знаю проблему и). затем измените его, добавьте соответствующие недостающие части и повторите попытку.
server {
listen 22222;
server_name localhost;
location / {
add_header Access-Control-Allow-Origin 'http://localhost:8080' always;
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Headers 'authorization'; #Почему это написано внутри, если вместо Access-Control-Allow-Origin? Потому что здесь будут проверяться только предполетные запросы
return 204;
}
proxy_pass http://localhost:59200;
}
}
В это время было обнаружено, что проблема с отчетами об ошибках вернулась к ситуации 1.
Тестирование подтвердило, что пока в if ($request_method = ‘OPTIONS’) записан add_header, внешняя конфигурация будет недействительной при выполнении предполетного запроса. Почему? ↓↓.
В официальной документации сказано следующее:
“ There could be several add_header directives. These directives are inherited from the previous level if and only if there are no add_header directives defined on the current level.
Это означает, что если на текущем уровне нет инструкции add_header, наследуется add_header предыдущего уровня. Напротив, если текущий уровень имеет add_header, он не должен иметь возможности наследовать add_header предыдущего уровня.
Модификация конфигурации заключается в следующем:
server {
listen 22222;
server_name localhost;
location / {
add_header Access-Control-Allow-Origin 'http://localhost:8080' always;
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin 'http://localhost:8080';
add_header Access-Control-Allow-Headers 'authorization';
return 204;
}
proxy_pass http://localhost:59200;
}
}
На этот раз, после модификации, я обнаружил, что междоменная проблема решена.
Однако, хотя вышеизложенное решает междоменную проблему, учитывая, что версия Nginx может быть обновлена в будущем, я не знаю, будет ли это правило изменено, учитывая, что этот метод записи может содержать два Access-Control-Allow-. Происхождение тоже имеет место. Не допускается, как описано ниже. Поэтому конфигурацию следует изменить следующим образом:
server {
listen 22222;
server_name localhost;
location / {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin 'http://localhost:8080';
add_header Access-Control-Allow-Headers 'authorization';
return 204;
}
if ($request_method != 'OPTIONS') {
add_header Access-Control-Allow-Origin 'http://localhost:8080' always;
}
proxy_pass http://localhost:59200;
}
}
Это еще не конец, продолжайте общаться ↓↓
Случай 4:
Более ранние API могут использовать только запросы POST и GET, а заголовок ответа на запрос Access-Control-Allow-Methods по умолчанию поддерживает только POST и GET между доменами. При возникновении других типов запросов также возникают междоменные исключения.
Например, я изменил запрошенный метод запроса интерфейса API с исходного GET на PUT и попробовал еще раз. На консоли будет выдана ошибка:
“ Access to XMLHttpRequest at ‘http://localhost:22222/api/Login/TestGet’ from origin ‘http://localhost:8080’ has been blocked by CORS policy: Method PUT is not allowed by Access-Control-Allow-Methods in preflight response.
Содержание ошибки также очень ясно. В этом предварительном запросе метод PUT не разрешен для использования в междоменном режиме. Нам нужно изменить конфигурацию Access-Control-Allow-Methods (если что-то отсутствует, я могу это сделать). просто добавим его сюда. После PUT вы можете добавить его самостоятельно), чтобы браузер знал, что сервер разрешен.
server {
listen 22222;
server_name localhost;
location / {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin 'http://localhost:8080';
add_header Access-Control-Allow-Headers 'content-type,authorization';
add_header Access-Control-Allow-Methods 'PUT';# Почему он добавляется только к этому if, а не к следующему if? Поскольку здесь будет проверяться только предполетный запрос, то, конечно, ничего страшного, если вы его добавите.
return 204;
}
if ($request_method != 'OPTIONS') {
add_header Access-Control-Allow-Origin 'http://localhost:8080' always;
}
proxy_pass http://localhost:59200;
}
}
Обратите внимание, что после изменения типа PUT заголовок ответа запроса Access-Control-Allow-Headers автоматически проверит заголовок запроса типа контента, что аналогично случаю 3. Просто восполните все пропущенное. Если тип контента не добавлен, будет сообщено о следующей ошибке. (Для простоты: Access-Control-Allow-Headers и Access-Control-Allow-Methods можно установить в *, что означает, что все они совпадают. Однако не рекомендуется устанавливать Access-Control-Allow-Origin в * . Из соображений безопасности ограничения Доменное имя очень необходимо.
После добавления их всех проблема решена. Сообщаемая здесь ошибка 405 заключается в том, что интерфейс на моем сервере открывает только GET и не открывает PUT. В этот момент я использую метод PUT для запроса этого интерфейса, поэтому интерфейс вернет это. код состояния.
Случай 5:
Наконец, позвольте мне поговорить о другой ситуации, то есть серверная часть обрабатывает междоменный доступ, и нет необходимости решать эту проблему самостоятельно (вот жалоба, некоторые серверные инженеры меняют код сервера для решения кросс-доменной проблемы). домен, но они не понимают принцип, поэтому могут найти его в Интернете. Фрагмент кода вставлен, что приводит к неполной обработке информации ответа, например. Метод не добавляется полностью, заголовки не добавляются в точку, тот, который вы используете, может не содержать тех, которые используются в реальном проекте, код статуса возврата запроса опций не добавляется и т. д., в результате чего Nginx использует общий конфигурации и может сообщать о следующих аномальных явлениях)
“ Access to XMLHttpRequest at ‘http://localhost:22222/api/Login/TestGet’ from origin ‘http://localhost:8080’ has been blocked by CORS policy: The ‘Access-Control-Allow-Origin’ header contains multiple values ‘*, http://localhost:8080’, but only one is allowed.
Это означает, что в этот момент возвращается несколько заголовков ответа на запрос Access-Control-Allow-Origin, но разрешен только один. В этом случае, конечно, вы можете изменить конфигурацию и удалить конфигурацию Access-Control-Allow-Origin. Однако при возникновении такой ситуации рекомендуется выбрать только одну из конфигураций Nginx и разрешения междоменных проблем на стороне сервера. (Обратите внимание, что если вы будете следовать моему методу написания выше, если $request_method = ‘OPTIONS’ Access-Control-Allow-Origin в этом случае не может быть удален. Просто удалите тот, который находится в !='OPTIONS', потому что, если это предполетный запрос, он будет возвращен напрямую, и запрос не будет перенаправлен на номер 5920. 0, если его тоже удалить, будет сообщаться о той же ошибке, что и в случае 1. Так почему же вы говорите, что междоменная проблема должна решаться на уровне кода сервера или с помощью прокси Nginx? это вверх, иначе люди, которые не понимают принцип, возможно, вы не сможете решить проблему, если найдете кусок кода, размещенный в Интернете)
Снова опубликуйте полную конфигурацию (заполните * в соответствии с вашими «предпочтениями»):
server {
listen 22222;
server_name localhost;
location / {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin 'http://localhost:8080';
add_header Access-Control-Allow-Headers '*';
add_header Access-Control-Allow-Methods '*';
add_header Access-Control-Allow-Credentials 'true';
return 204;
}
if ($request_method != 'OPTIONS') {
add_header Access-Control-Allow-Origin 'http://localhost:8080' always;
add_header Access-Control-Allow-Credentials 'true';
}
proxy_pass http://localhost:59200;
}
}
или:
server {
listen 22222;
server_name localhost;
location / {
add_header Access-Control-Allow-Origin 'http://localhost:8080' always;
add_header Access-Control-Allow-Headers '*';
add_header Access-Control-Allow-Methods '*';
add_header Access-Control-Allow-Credentials 'true';
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_pass http://localhost:59200;
}
}
Наконец, это статья о процессе решения междоменных проблем. Если вы ее внимательно прочитаете, я думаю, вы легко сможете понять ее и решить проблему самостоятельно при реальном использовании. Надеюсь, это поможет всем. все основано на моем понимании собственного тестового кода. Если в моем понимании что-то не так, пожалуйста, поправьте меня.
Если эта статья оказалась для вас полезной или вдохновляющей, нажмите трижды: «Нравится», «Переслать» и прочитайте. Ваша поддержка — моя самая большая мотивация продолжать писать.