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

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