Вопрос или проблема
У меня есть следующие настройки сервера, которые работают для одного URL, но, похоже, не работают для другого URL.
location / {
proxy_buffers 16 4k;
proxy_buffer_size 2k;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port 443;
proxy_pass http://10.4.1.81/;
# Это используется для обработки множества перенаправлений 301, которые выполняет сервер
proxy_intercept_errors on;
error_page 301 302 307 = @handle_redirects;
}
location @handle_redirects {
set $saved_redirect_location '$upstream_http_location';
proxy_pass $saved_redirect_location;
}
Когда я перехожу по следующему URL:
https://lfdocs.mohave.gov/bos/0/doc/1652027/Page1.aspx
я получаю следующую ошибку от Nginx
2020/12/03 19:10:40 [error] 31251#31251: *1 invalid URL prefix in "/bos/CookieCheck.aspx?redirect=%2fbos%2fDocView.aspx%3fdbid%3d0%26id%3d1652027%26page%3d1" while sending to client, client: 10.10.82.151, server: lfdocs.mohave.gov, request: "GET /bos/0/doc/1652027/Page1.aspx HTTP/2.0", host: "lfdocs.mohave.gov"
Я провел небольшое исследование, но не могу понять. Есть ли советы?
Спасибо
Обновление
Проблема кажется связана с тем, что правильные URL являются корректными. При неудаче это происходит из-за некорректного URL.
-
Используя echo $saved_redirect_location;
Успех
URL:
https://lfdocs.mohave.gov/Forms/RequestToSpeak
Возврат:
https://10.4.1.81/Forms/RequestToSpeak
Неудача:
URL:
https://lfdocs.mohave.gov/bos/0/doc/1652027/Page1.aspx
Возвращает:
/bos/CookieCheck.aspx?redirect=%2fbos%2fDocView.aspx%3fdbid%3d0%26id%3d1652027%26page%3d1
-
Используя echo http://10.4.1.81$saved_redirect_location;
Неудача
URL:
https://lfdocs.mohave.gov/Forms/RequestToSpeak
Возврат:
http://10.4.1.81https://10.4.1.81/Forms/RequestToSpeak
Успех
URL:
https://lfdocs.mohave.gov/bos/0/doc/1652027/Page1.aspx
Возвращает:
используя $saved_redirect_location для proxy_pass, есть ли способ проверить, существует ли домен, и если нет, то добавить его?
Обновление
Мое решение было следующим:
location @handle_redirects {
set $saved_redirect_location '$upstream_http_location';
# Если IP существует, просто прокси передача
if ($saved_redirect_location ~* "10.4.1.81") {
proxy_pass $saved_redirect_location;
}
# Если IP не существует, добавляем его в начало
if ($saved_redirect_location !~* "10.4.1.81") {
proxy_pass http://10.4.1.81$saved_redirect_location;
}
}
Это решение, которое в итоге сработало для меня. Спасибо, Иван, за совет.
location @handle_redirects {
set $saved_redirect_location '$upstream_http_location';
# Если IP существует, просто прокси передача
if ($saved_redirect_location ~* "10.4.1.81") {
proxy_pass $saved_redirect_location;
}
# Если IP не существует, добавляем его в начало
if ($saved_redirect_location !~* "10.4.1.81") {
proxy_pass http://10.4.1.81$saved_redirect_location;
}
}
Ответ или решение
Ваша проблема связана с некорректной обработкой URL-адресов, возвращаемых от upstream-сервера в вашем конфигурационном файле Nginx. Описание ошибки "invalid URL prefix" указывает на то, что Nginx сталкивается с некорректной структурой URL при попытке перенаправления. Позвольте предложить теоретическое объяснение, примеры для лучшего понимания и рекомендации по применению вашего решения.
Теория
Когда Nginx используется в качестве реверс-прокси, он пересылает запросы от клиента к upstream-серверу и возвращает ответ обратно клиенту. Иногда upstream-сервер может вернуть редирект HTTP-кодами, такими как 301 или 302, при этом в заголовке ‘Location’ содержится новый URL, на который необходимо перенаправить запрос. Поскольку ваш Nginx сконфигурирован для перехвата таких ошибок с помощью директивы proxy_intercept_errors on;
, он попадает в пользовательскую локацию @handle_redirects
, где происходит обработка этих случаев.
Проблема в том, что не все URL от upstream-сервера корректно подставляются в proxy_pass
. В вашем случае, если URL начинается без домена или IP, Nginx видит это как некорректный префикс и выдаёт ошибку.
Пример
Рассмотрим детали вашего конфигурационного кода:
location / {
# ...
proxy_pass http://10.4.1.81/;
proxy_intercept_errors on;
error_page 301 302 307 = @handle_redirects;
}
location @handle_redirects {
set $saved_redirect_location '$upstream_http_location';
# Неправильная обработка URL без домена/IP
proxy_pass $saved_redirect_location;
}
Если '$upstream_http_location'
возвращает значение без домена/IP, Nginx не знает, как его интерпретировать, поскольку рассматривает данный фрагмент как часть относительного пути, что и вызывает проблему.
Применение
Ваше итоговое решение исправляет это, проверяя, содержит ли '$saved_redirect_location'
указанный IP-адрес, и, в отсутствии оного, добавляя его вручную. Это гарантирует, что proxy_pass
всегда получает полный URL. Рассмотрим код вашего решения:
location @handle_redirects {
set $saved_redirect_location '$upstream_http_location';
# Проверка наличия IP-адреса и соответствующее действие
if ($saved_redirect_location ~* "10.4.1.81") {
proxy_pass $saved_redirect_location;
} else {
proxy_pass http://10.4.1.81$saved_redirect_location;
}
}
Это решение эффективно, так как оно анализирует структуру URL и корректирует её до безопасного состояния. В случае отсутствия полного доменного имени или IP, оно добавляет недостающую часть URL, делая его пригодным для дальнейшего использования.
Заключение
Чтобы улучшить вашу конфигурацию и избежать подобных проблем в будущем, возможно, стоит рассмотреть добавление логирования для отслеживания потенциально проблемных запросов. Кроме того, включение другого уровня проверки допустимости URL, например, через пользу регулярных выражений или иной обработки заголовков, поможет быстрее идентифицировать и устранять подобные баги.
Ваш метод конфигурации и конечное решение являются элегантными и подчеркивают необходимость динамической обработки URL-адресов в различных сетевых конфигурациях. Это гарантирует корректную работу реверс-прокси даже при нестандартных отклонениях в структуре возвращаемых upstream URL.
Надеюсь, это объяснение помогло прояснить механизмы, приведшие к возникновению ошибки, и предложенные улучшения помогут в дальнейшем избегать похожих ситуаций.