Избегайте параметров запроса на декодирование nginx на proxy_pass (что эквивалентно AllowEncodedSlashes NoDecode)
Я использую nginx в качестве загрузочного баллона перед несколькими котами. В своих входящих запросах я закодировал параметры запроса. Но когда запрос поступает в tomcat, параметры декодируются:
входящий запрос к nginx:
curl -i "http://server/1.1/json/T;cID=1234;pID=1200;rF=http%3A%2F%2Fwww.google.com%2F"
входящий запрос на tomcat:
curl -i "http://server/1.1/json/T;cID=1234;pID=1200;rF=http:/www.google.com/"
Я не хочу, чтобы параметры моего запроса трансформировались, потому что в этом случае мой кот выдает ошибку 405.
Моя конфигурация nginx следующая:
upstream tracking {
server front-01.server.com:8080;
server front-02.server.com:8080;
server front-03.server.com:8080;
server front-04.server.com:8080;
}
server {
listen 80;
server_name tracking.server.com;
access_log /var/log/nginx/tracking-access.log;
error_log /var/log/nginx/tracking-error.log;
location / {
proxy_pass http://tracking/webapp;
}
}
В моей текущей конфигурации балансировки нагрузки Apache у меня есть директива AllowEncodedSlashes, которая сохраняет мои закодированные параметры:
AllowEncodedSlashes NoDecode
Мне нужно перейти с Apache на Nginx.
Мой вопрос совершенно противоположен этому вопросу: избегайте экранирования параметров запроса nginx на proxy_pass
Ответы
Ответ 1
Наконец-то я нашел решение: мне нужно передать $request_uri
:
location / {
proxy_pass http://tracking/webapp$request_uri;
}
Таким образом, символы, которые были закодированы в исходном запросе, не будут декодированы, то есть будут переданы как-на прокси-сервер.
Ответ 2
Ответ на ответ хорош, но он не работает с подзонами. В этом случае более общий ответ:
location /path/ {
if ($request_uri ~* "/path/(.*)") {
proxy_pass http://tracking/webapp/$1;
}
}
Ответ 3
Существует одна документированная опция для директивы Nginx proxy_pass
Если необходимо передать URI в необработанной форме, тогда директива proxy_pass должна использоваться без части URI:
location /some/path/ {
proxy_pass http://127.0.0.1;
}
так что в вашем случае это может быть так. Не беспокойтесь о URI запроса, он будет передан вышестоящим серверам.
location / {
proxy_pass http://tracking;
}
Надеюсь, поможет.
Ответ 4
Обратите внимание, что декодирование URL, обычно называемое $uri
"нормализацией" в документации по nginx, происходит до IFF:
-
либо любой URI указывается в самом proxy_pass
, даже если только конечный слеш сам по себе,
-
или URI изменяется во время обработки, например, путем rewrite
.
Оба условия четко задокументированы на http://nginx.org/r/proxy_pass (выделено мной):
-
Если директива proxy_pass
указана с URI, то при передаче запроса на сервер часть нормализованного URI запроса, соответствующая местоположению, заменяется на URI, указанный в директиве
-
Если proxy_pass
указан без URI, URI запроса передается на сервер в той же форме, что и отправленный клиентом при обработке исходного запроса, или полный URI нормализованного запроса при обработке измененного URI
Решение зависит от того, нужно ли вам изменить URL-адрес между внешним и внутренним интерфейсом.
-
Если изменение URI не требуется:
# map '/foo' to '/foo':
location /foo {
proxy_pass http://localhost:8080; # no URI -- not even just a slash
}
-
В противном случае, если вам нужно поменять местами /api
map /api
интерфейса с /app
на внутреннем, то вы можете получить исходный URI из переменной $request_uri
и использовать директивы rewrite
над переменной $uri
аналогично DFA (кстати, если вы хотите больше rewrite
действие DFA, взгляните на mdoc.su). Обратите внимание, что return 400
часть return 400
необходима в случае, если кто-то попытается обойти ваше второе правило перезаписи, так как оно не будет совпадать с чем-то вроде //api/
.
# map '/api' to '/app':
location /foo {
rewrite ^ $request_uri; # get original URI
rewrite ^/api(/.*) /app$1 break; # drop /api, put /app
return 400; # if the second rewrite won't match
proxy_pass http://localhost:8080$uri;
}
-
Если вы просто хотите добавить префикс для бэкэнда, вы можете сразу использовать переменную $request_uri
:
# add '/webapp' to the backend:
location / {
proxy_pass http://localhost:8080/webapp$request_uri;
}
Возможно, вы также захотите взглянуть на связанный ответ, который показывает некоторые тестовые прогоны кода, аналогичного приведенному выше.
Ответ 5
В некоторых случаях проблема не в стороне nginx - вы должны установить кодировку uri на разъеме Tomcat на UTF-8.