您现在的位置是:首页 >技术教程 >Nginx 自动url decode探究及如何避免url decode网站首页技术教程
Nginx 自动url decode探究及如何避免url decode
最近发现Nginx proxy_pass后端URI进行了decode的问题,网上查了查资料,这里汇总一下。
参考stackoverflow:
Nginx pass_proxy subdirectory without url decoding - Stack Overflow
场景
有个查询项目详情接口 /projects/{name},正好我们要查询名称为 root/name 的项目,此时我们不能直接访问 /projects/root/name,这样会被系统误认为是要查询名称为 root 的项目。所以,在实际开发中需要将 root/name 先进行UrlEncode(编码)再拼接到url上,即 /projects/root%2fname
最近在访问Nginx代理的服务时,此类url的api调用一直是404的异常,然而不通过nginx代理,直接访问后端服务时,此类url的api调用又是正常的。
问题探究
通过搜罗网上的相关资料,发现是nginx自动进行 UrlDecode(解码)的问题。
下面对各种nginx配置进行实验,探究如何避免自动UrlDecode:
编写 nginx.conf
第一个server配置就是我们常规的代理配置,会将请求代理后端的服务上去,比如运行的springboot项目,tomcat、jetty等等服务。
配置文件中有多段location配置,我们逐一验证。验证某一端配置时,将其他配置时注释掉!
第二个server配置模拟被代理的服务(即上面说的tomcat、jetty等等)。这个server直接将请求的uri返回。所以可以通过返回信息得知被代理的服务接收到的url是否被decode。
events {
worker_connections 1024;
}
http {
server {
listen 8088;
server_name localhost;
location / {
proxy_pass http://127.0.0.1:8099/;
}
#location / {
# proxy_pass http://127.0.0.1:8099;
#}
#location / {
# proxy_pass http://127.0.0.1:8099$1;
#}
#location / {
# if ($request_uri ~* ^/(.*)$) {
# proxy_pass http://127.0.0.1:8099/$1;
# }
#}
}
# 此server模拟被代理的服务。通过观察此服务接收到的请求url,确定url通过nginx时是否被decode
server {
listen 8099;
server_name localhost;
location / {
add_header request $request;
# $request_uri是Nginx内置的变量,表示请求的uri。
# 这里直接将uri返回。所以可以通过返回信息得知被代理的服务接收到的url是否被decode。
default_type text/html; return 200 $request_uri;
}
}
}
启动Nginx .
ginx.exe
请求接口 /projects/root%2fname,通过返回值判断nginx是否自动进行UrlDecode。(验证某一段配置时,需将其他配置时注释掉!)
开启第1段location配置
注释掉其他location,重载配置 .
ginx.exe -s reload
location / {
proxy_pass http://127.0.0.1:8099/;
}
此处使用 curl 命令发送请求,当然也可以使用postman等等,怎么方便怎么来。
$ curl -s localhost:8088/projects/root%2fname
/projects/root/name
结论:如上,返回结果是 /projects/root/name,即后端服务接收到的请求uri,说明这种形式的配置nginx会自动进行UrlDecode。
开启第2段location配置
注释掉其他location,重载配置 .
ginx.exe -s reload
location / {
proxy_pass http://127.0.0.1:8099;
}
$ curl -s localhost:8088/projects/root%2fname
/projects/root%2fname
结论:返回结果是 /projects/root%2fname,说明这种形式的配置nginx不会自动进行UrlDecode。(可行办法1)
开启第3段location配置
注释掉其他location,重载配置 .
ginx.exe -s reload
location / {
proxy_pass http://127.0.0.1:8099$1;
}
$ curl -s localhost:8088/projects/root%2fname
/projects/root%2fname
结论:返回结果是 /projects/root%2fname,说明这种形式的配置nginx不会自动进行UrlDecode。(可行办法2)
开启第4段location配置
注释掉其他location,重载配置 .
ginx.exe -s reload
location / {
if ($request_uri ~* ^/(.*)$) {
proxy_pass http://127.0.0.1:8099/$1;
}
}
$ curl -s localhost:8088/projects/root%2fname
/projects/root%2fname
结论:返回结果是 /projects/root%2fname,说明这种形式的配置nginx不会自动进行UrlDecode。(可行办法3)
另外可行的location配置
# map `/api` to `/app`:
location /foo {
rewrite ^ $request_uri; # get original URI
rewrite ^/api(/.*) /app$1 break; # drop /api, put /app
return 400; # if the second rewrite won't match
proxy_pass http://localhost:8080$uri;
}
总结
配置2、配置3、配置4均可避免Nginx 自动进行 url decode。
# 配置2
location / {
proxy_pass http://127.0.0.1:8099;
}
# 配置3
location / {
proxy_pass http://127.0.0.1:8099$1;
}
# 配置4
location / {
if ($request_uri ~* ^/(.*)$) {
proxy_pass http://127.0.0.1:8099/$1;
}
}
或者:
location ~ ^/gate { if ($request_uri ~* ^/gate/(.*)$) { proxy_pass http://127.0.0.1:8081/$1; } }
# 配置5
location /foo {
rewrite ^ $request_uri; # get original URI
rewrite ^/api(/.*) /app$1 break; # drop /api, put /app
return 400; # if the second rewrite won't match
proxy_pass http://localhost:8080$uri;
}
参考
nginx proxy_pass and URL decoding - Stack Overflow
Nginx pass_proxy subdirectory without url decoding - Stack Overflow
Nginx 自动url decode探究及如何避免url decode_nginx urldecode_markix的博客-CSDN博客