Избегайте параметров запроса на декодирование nginx на proxy_pass (что эквивалентно AllowEncodedSlashes NoDecode) - программирование
Подтвердить что ты не робот

Избегайте параметров запроса на декодирование 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

4b9b3361

Ответ 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.