nginx $uri 是 url 解码

Car*_*rós 9 rewrite nginx encoding

我使用nginx作为反向代理,我有 2 条规则,例如:

location ~ ^/indirect {
  rewrite ^/indirect(.*) /foobar$1;
}

location ~ ^/foobar {
  set $url http://example.com/something/index.php?var1=hello&access=$scheme://$host$uri;
  proxy_pass $url;
}
Run Code Online (Sandbox Code Playgroud)

因此,正如您所看到的,我将$uri变量作为参数传递给代理页面(该$uri变量是 nginx 的,请参阅http core module文档)。

问题是,如果我访问http://example.com/foobar/hello%20world,该$uri变量包含 /foobar/hello world(如您所见,%20已被其 url 解码值替换,一个空格)。然后,nginx 在执行 proxy_pass 行(未联系后端)之前返回 http 状态代码 400(错误请求)。

还有可用的变量$request_uri,它保存客户端发出的原始请求 URI,因此在这种情况下,它将保存正确的值和%20序列。但是我不能使用它,因为如果客户端通过/indirect路径,$request_uri将包含/indirect/...而我希望access传递给后端的参数始终为/foobar/...

有多个indirect类似规则(这是针对 DAV/calDAV/cardDAV 服务器,并且有多个客户端连接到多个路径,所以我需要这些类似indirect规则),所以在proxy_pass那里做是不可行的,并且有直接进入/foobar路径的客户端。

那么有没有什么方法可以$uri不用 url 解码呢?

可能无法接受的事情:

  • 发送双重编码的请求,因为请求可能来自我无法控制的客户端
  • 在 eacy 间接规则和“直接”规则中多次指定最终 url,因为它会导致维护问题。

小智 2

我发现的唯一方法是使用HttpSetMiscModule ,如下所示:

location ~
 ^/indirect {
  set_escape_uri $key $1;
  rewrite ^/indirect(.*) /foobar$key;
}

location ~ ^/foobar {
  set_escape_uri $key $uri;
  set $url http://example.com/something/index.php?var1=hello&access=$scheme://$host$key;
  proxy_pass $url;
}
Run Code Online (Sandbox Code Playgroud)

如果有人知道更好的方法(无需使用外部模块编译 nginx,因为我没有 root 访问权限)请告诉我!