当我浏览此 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 重写规则?
答案1
引用瓦伦丁·V·巴尔捷涅夫(谁应该获得这个答案的全部荣誉):
引自文档:
如果指定了 proxy_pass带有 URI,在向服务器传递请求时,规范化与位置匹配的请求 URI 将被指令中指定的 URI 替换
如果
proxy_pass
指定无 URI,请求 URI 以客户端处理原始请求时发送的相同形式传递给服务器您的情况下的正确配置是:
location /foo { proxy_pass http://localhost:8080; }
答案2
请注意,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,要么是使用一个巧妙的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;
}
你可以在 Stack Overflow 的相关回答中查看,包括对照组。