Назад | Перейти на главную страницу

Отключение декодирования URL в прокси nginx

Когда я перехожу к этому URL: http://localhost:8080/foo/%5B-%5D сервер (nc -l 8080) получает как есть:

GET /foo/%5B-%5D HTTP/1.1

Однако, когда я проксирую это приложение через nginx (1.1.19):

location /foo {
        proxy_pass    http://localhost:8080/foo;
}

Тот же запрос, направленный через порт nginx, пересылается с декодированным путем:

GET /foo/[-] HTTP/1.1

Декодированные квадратные скобки в пути GET вызывают ошибки на целевом сервере (Статус HTTP 400 - недопустимый символ в пути ...) по мере того, как они прибывают незамеченными.

Есть ли способ отключить декодирование URL-адресов или закодировать его, чтобы целевой сервер получил точно такой же путь при маршрутизации через nginx? Какое-то умное правило перезаписи URL?

Цитирование Валентин Васильевич Бартенев (кто должен получить полную оценку за этот ответ):

Цитата из документация:

  • Если указан proxy_pass с URI, при передаче запроса на сервер, часть нормализованный URI запроса, соответствующий местоположению, заменяется URI, указанным в директиве

  • Если proxy_pass указан без URI, URI запроса передается на сервер в той же форме, что и клиент при обработке исходного запроса.

Правильная конфигурация в вашем случае будет:

location /foo {
   proxy_pass http://localhost:8080;
}

Обратите внимание, что декодирование 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


Решение состоит в том, чтобы либо опустить URI, как в случае OPs, либо действительно использовать умный rewrite правило:

# map `/foo` to `/foo`:
location /foo {
    proxy_pass  http://localhost:8080;  # no URI -- not even just a slash
}

# map `/foo` to `/bar`:
location /foo {
    rewrite  ^  $request_uri;            # get original URI
    rewrite  ^/foo(/.*)  /bar$1  break;  # drop /foo, put /bar
    return 400;   # if the second rewrite won't match
    proxy_pass    http://localhost:8080$uri;
}

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