在 nginx 代理中禁用 URL 解码

Tom*_*icz 25 rewrite url nginx

当我浏览到这个 URL 时:http://localhost:8080/foo/%5B-%5Dserver ( nc -l 8080) 按原样接收它:

GET /foo/%5B-%5D HTTP/1.1
Run Code Online (Sandbox Code Playgroud)

但是,当我通过 nginx (1.1.19) 代理此应用程序时:

location /foo {
        proxy_pass    http://localhost:8080/foo;
}
Run Code Online (Sandbox Code Playgroud)

通过 nginx 端口路由的相同请求转发路径解码:

GET /foo/[-] HTTP/1.1
Run Code Online (Sandbox Code Playgroud)

GET 路径中的解码方括号导致目标服务器中的错误(HTTP 状态 400 - 路径中的非法字符...),因为它们未转义到达。

有没有办法禁用 URL 解码或将其编码回来,以便目标服务器在通过 nginx 路由时获得完全相同的路径?一些巧妙的 URL 重写规则?

Tom*_*icz 21

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

来自文档的引用:

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

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

在您的情况下正确的配置是:

location /foo {
   proxy_pass http://localhost:8080;
}
Run Code Online (Sandbox Code Playgroud)

  • 我不得不将 `http://localhost:8080/` 更改为 `http://localhost:8080`,以防有人遇到和我一样的情况。 (10认同)
  • 为什么 Nginx 在将 URI 传递给后端服务器之前对其进行解码?如果它保持 URI 不变,不是更有意义吗? (4认同)

cns*_*nst 9

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

  • 任何 URI 都在proxy_pass其自身内指定,即使只是尾部斜杠本身,

  • 或者,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;
}
Run Code Online (Sandbox Code Playgroud)

您可以在相关的 Stack Overflow 答案中看到它,包括控制组。

  • 这里的文档令人困惑。两种形式都包含一个 URI。_path component_ 存在于一个中而另一个中缺失。 (2认同)
  • 是只有我这样还是标准行为很古怪?我们不希望仅仅因为我们碰巧重写到路径而不是根目录而更改 URL! (2认同)