Решайте междоменные проблемы с помощью Nginx
Решайте междоменные проблемы с помощью Nginx

Научите вас, как быстро и легко решать междоменные проблемы с помощью Nginx.

Когда вы сталкиваетесь с междоменной проблемой, не сразу копируйте ее и пробуйте. Пожалуйста, внимательно прочитайте эту статью перед обработкой. Я верю, что это может помочь вам.

Подготовка перед анализом:

Адрес внешнего веб-сайта: http://localhost:8080.

URL-адрес сервера: http://localhost:59200.

Во-первых, убедитесь, что сервер не обрабатывает междоменные проблемы. Во-вторых, используйте почтальона, чтобы проверить, нормально ли работает интерфейс сервера.

картина
картина

Когда веб-сайт 8080 обращается к интерфейсу сервера, возникает междоменная проблема. Как ее решить? Далее я перечислил различные ситуации, возникающие в разных доменах, и решил их через прокси-сервер nginx (то же самое происходит и в фоновом режиме, если вы понимаете принцип).

Междоменный подход в основном включает в себя 4 заголовка ответа:

  • Access-Control-Allow-Origin использовать Разрешено в настройках Междоменный адрес источника запроса домена (Предполетные запросы и официальные запросы находятся на сайте Междоменный. домен будет проверяться каждый раз)
  • Access-Control-Allow-Headers Междоменный Специальные информационные поля заголовка, которые разрешено переносить по домену. (Только при предполетной проверке запроса)
  • Access-Control-Allow-Methods Междоменный разрешенные доменом методы запроса или HTTP-глаголы (Только при предполетной проверке запроса)
  • Access-Control-Allow-Credentials Междоменный разрешен? доменделатьиспользоватьcookies,Если вы хотите Междоменный Если домен использует файлы cookie, вы можете добавить этот заголовок ответа на запрос и установить значение true (установка или отключение этого параметра не повлияет на отправку запроса, а повлияет только на запрос в Междоменный Следует ли сохранять файлы cookie при поиске, но если они установлены, необходимо установить как предполетные запросы, так и формальные запросы). Но не рекомендуется домен useuse (в проекте использовался использовать, но он нестабилен и некоторые браузеры не могут его перенести) без необходимости, потому что альтернатив много.

Во многих статьях в Интернете говорится, что добавление этих заголовков ответов непосредственно в Nginx может решить междоменные проблемы. Конечно, большинство случаев можно решить, но я считаю, что есть еще много случаев, когда о междоменных проблемах все равно будут сообщать. конфигурация правильная.

Что такое предполетный запрос?:когда произойдет Междоменный доменусловное время,Браузер сначала запрашивает сервер,Находится ли доменное имя текущей веб-страницы в списке разрешений сервера.,И какие HTTP-глаголы и поля заголовка можно использовать. получить только положительный ответ,Браузер выдаст формальный запрос XMLHttpRequest.,В противном случае будет сообщено об ошибке. Как показано ниже

картина
картина

Приступаем к симуляции:

Порт прокси Nginx: 22222, конфигурация следующая

Язык кода:javascript
копировать
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 следующим образом (красная часть — добавленная часть), заполните все недостающее, это очень просто и понятно.

Язык кода:javascript
копировать
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, а другая информация заголовка будет переносим обратно без добавления всегда), тогда попробуем

Язык кода:javascript
копировать
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).

Язык кода:javascript
копировать
 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, чтобы браузер знал, что перенос этой информации заголовка распознается сервером как законный. Здесь я несу авторизацию, а остальные могут быть токенами. Я знаю проблему и). затем измените его, добавьте соответствующие недостающие части и повторите попытку.

Язык кода:javascript
копировать
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 предыдущего уровня.

картина
картина

Модификация конфигурации заключается в следующем:

Язык кода:javascript
копировать
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-. Происхождение тоже имеет место. Не допускается, как описано ниже. Поэтому конфигурацию следует изменить следующим образом:

Язык кода:javascript
копировать
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 вы можете добавить его самостоятельно), чтобы браузер знал, что сервер разрешен.

Язык кода:javascript
копировать
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? это вверх, иначе люди, которые не понимают принцип, возможно, вы не сможете решить проблему, если найдете кусок кода, размещенный в Интернете)

Снова опубликуйте полную конфигурацию (заполните * в соответствии с вашими «предпочтениями»):

Язык кода:javascript
копировать
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; 
        }
    }

или:

Язык кода:javascript
копировать
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; 
        }
    }

Наконец, это статья о процессе решения междоменных проблем. Если вы ее внимательно прочитаете, я думаю, вы легко сможете понять ее и решить проблему самостоятельно при реальном использовании. Надеюсь, это поможет всем. все основано на моем понимании собственного тестового кода. Если в моем понимании что-то не так, пожалуйста, поправьте меня.

Подвести итог

Если эта статья оказалась для вас полезной или вдохновляющей, нажмите трижды: «Нравится», «Переслать» и прочитайте. Ваша поддержка — моя самая большая мотивация продолжать писать.

boy illustration
Введение в параметры конфигурации большого экрана мониторинга Grafana (2)
boy illustration
В статье «Научно-популярная статья» подробно объясняется протокол NTP: анализ точной синхронизации времени.
boy illustration
Пример разработки: серверная часть Java и интерфейсная часть vue реализуют функции комментариев и ответов.
boy illustration
Nodejs реализует сжатие и распаковку файлов/каталогов.
boy illustration
SpringBootИнтегрироватьEasyExcelСложно реализоватьExcelлистимпортировать&Функция экспорта
boy illustration
Настройка среды под Mac (используйте Brew для установки go и protoc)
boy illustration
Навыки разрешения конфликтов в Git
boy illustration
Распределенная система журналов: развертывание Plumelog и доступ к системе
boy illustration
Артефакт, который делает код элегантным и лаконичным: программирование на Java8 Stream
boy illustration
Spring Boot(06): Spring Boot в сочетании с MySQL создает минималистскую и эффективную систему управления данными.
boy illustration
Как использовать ArrayPool
boy illustration
Интегрируйте iText в Spring Boot для реализации замены контента на основе шаблонов PDF.
boy illustration
Redis реализует очередь задержки на основе zset
boy illustration
Получить текущий пакет jar. path_java получает файл jar.
boy illustration
Краткое обсуждение высокопроизводительного шлюза Apache ShenYu
boy illustration
Если вы этого не понимаете, то на собеседовании даже не осмелитесь сказать, что знакомы с Redis.
boy illustration
elasticsearch медленный запрос, устранение неполадок записи, запрос с подстановочными знаками
boy illustration
По какому стандарту взимается плата за обслуживание программного обеспечения?
boy illustration
IP-адрес Получить
boy illustration
【Java】Решено: org.springframework.web.HttpRequestMethodNotSupportedException
boy illustration
Native js отправляет запрос на публикацию_javascript отправляет запрос на публикацию
boy illustration
.net PDF в Word_pdf в Word
boy illustration
[Пул потоков] Как Springboot использует пул потоков
boy illustration
Подробное объяснение в одной статье: Как работают пулы потоков
boy illustration
Серия SpringCloud (6) | Поговорим о балансировке нагрузки
boy illustration
IDEA Maven может упаковать все импортное полностью красное решение — универсальное решение.
boy illustration
Последний выпуск 2023 года, самое полное руководство по обучению Spring Boot во всей сети (с интеллект-картой).
boy illustration
[Решено — Практическая работа] SaTokenException: запрос не может быть получен в контексте, отличном от Интернета. Решение проблем — Практическая работа.
boy illustration
HikariPool-1 - Connection is not available, request timed out after 30000ms
boy illustration
Power Query: автоматическое суммирование ежемесячных данных с обновлением одним щелчком мыши.