在Nginx代理中禁用URL解码


21

当我浏览到该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重写规则?


Answers:


19

引用Valentin V. Bartenev(谁应该得到此答案的全部功劳):

来自文档的报价:

  • 如果使用URI指定proxy_pass ,则在将请求传递到服务器时,与该位置匹配的规范化请求URI的一部分将由伪指令中指定的URI替换。

  • 如果proxy_pass指定为不带URI,则将请求URI以与客户端在处理原始请求时发送的格式相同的格式传递给服务器

您的情况下正确的配置为:

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

8
我必须更改http://localhost:8080/http://localhost:8080万一有人遇到与我相同的情况。
herrtim

4
为什么Nginx在将URI传递到后端服务器之前会对其进行解码?如果它保持URI不变,那会更有意义吗?
platypus 2014年

@platypus,它将一直保持不变,直到您明确开始执行替换操作为止
cnst

2

请注意,URL解码(通常在Nginx文档中称为$uri“规范化”)发生在后端IFF之前:

  • 要么在proxy_pass其内部指定了任何URI ,即使仅是尾部的斜杠本身,

  • 或者,在处理过程中,例如,通过更改URI rewrite


这两个条件都在http://nginx.org/r/proxy_pass(着重强调)中明确记录:

  • 如果使用URIproxy_pass指定了伪指令,那么当请求传递到服务器时,与该位置匹配的规范化请求URI 的一部分将由伪指令中指定的URI替换。

  • 如果proxy_pass指定为不带URI,则将请求URI以与原始请求处理时客户端发送的格式相同的格式传递给服务器,或者处理更改的URI 传递完整的规范化请求URI。


解决方案是在OP的情况下要么省略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答案中看到它,包括控制组。


这里的文档令人困惑。两种形式都包含一个URI。它是一个中存在而另一个中不存在的路径组件
迈克尔·汉普顿

@MichaelHampton,我不同意-PATH通常称为URI,因此,没有路径的路径不包含URI。
cnst

当然,仅相对路径也可以是有效的URL。关键是,其余的也是有效的URI(例如http://localhost:8080)。如果您不同意,你可以把它与RFC 3986.的作者
迈克尔·汉普顿

@MichaelHampton不幸的是,似乎方案和路径对于URI是强制性的,权限,参数,片段是可选的
Norman Xu
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.