您现在的位置是:首页 >技术教程 >Nginx 自动url decode探究及如何避免url decode网站首页技术教程

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

zzhongcy 2023-07-14 12:00:02
简介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博客

https://www.cnblogs.com/hallwong/p/10516226.html

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。