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

    技术2022-07-11  77

    场景

    有个查询项目详情接口 /projects/{name},正好我们要查询名称为 root/name 的项目,此时我们不能直接访问 /projects/root/name,这样会被系统误认为是要查询名称为 root 的项目。所以,在实际开发中需要将 root/name 先进行UrlEncode(编码)再拼接到url上,即 /projects/root/name

    最近在访问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 .\nginx.exe

    请求接口 /projects/root/name,通过返回值判断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/name /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/name /projects/root/name

    结论:返回结果是 /projects/root/name,说明这种形式的配置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/name /projects/root/name

    结论:返回结果是 /projects/root/name,说明这种形式的配置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/name /projects/root/name

    结论:返回结果是 /projects/root/name,说明这种形式的配置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 https://gitlab.com/gitlab-org/gitlab/-/issues/18775#note_215017836


    end

    Processed: 0.009, SQL: 9