Nginx 自动url decode探究及如何避免url decode

场景

有个查询项目详情接口 /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:

  1. 编写 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;
		}
	}
}
  1. 启动Nginx .\nginx.exe

  2. 请求接口 /projects/root%2fname,通过返回值判断nginx是否自动进行UrlDecode。(验证某一段配置时,需将其他配置时注释掉!)

  • 开启第1段location配置,注释掉其他location,重载配置 .\nginx.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,重载配置 .\nginx.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,重载配置 .\nginx.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,重载配置 .\nginx.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)

总结

配置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;
	}
}

reference:
使用Nginx代理S3时,需要禁用URL解码。
如何避免Nginx将url decode
Nginx 官方文档 http://nginx.org/en/docs/
Nginx 内置变量 http://nginx.org/en/docs/varindex.html


end

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章