我们基础架构是用的springcloudalibaba的微服务。有一个域名原来是直接跳转到服务的ip:port,没走微服务的gateway,因此导致了一些安全问题。为了修复安全问题,把域名指向了nginx,在nginx里指向gateway,通过鉴权后再到服务。

配置如下:


upstream gateway{
	server 192.168.9.xxx:xxxx;
	server 192.168.9.xxx:xxxx;
}


server {
        listen       80;
        server_name         xxxx.xxxx.com.cn;
        access_log          /var/log/nginx/xxxx.access.log main buffer=32k flush=5s;
        error_log           /var/log/nginx/xxxx.error.log;

        location / {
	        proxy_read_timeout  1200;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_buffering off;
            proxy_pass http://gateway/服务名xxx/;
         }
		 
        # 使用正则表达式匹配/actuator的所有路径  
        location ~ ^/actuator {  
            return 403; # 返回403 Forbidden  
        }
    }

就这样上线了。由于是对外开放的系统,谁都能来调,大家传参方式各异。上线后立刻发现有一部分请求一直报错,原来是没有问题的。于是开始调查。

服务日志显示过来的参数是这样的:

{"xxxx":["%7B%22xxxx%22:[%7B%22xxxx%22:%22test001%22,%22xxxx%22:%22%E5%B0%8F%E6%98%8E%22,%22xxxx%22:%22test001@qq.com%22%7D%7D]%7D"],"xxxx":["44A1BBD338B4467FC9733DE252DCAED0"]}

原本应该是正常的内容,比如汉字啊什么的,现在多了好多的百分号什么的,汉字也不展示了,像是被什么编码过了。

然后去看gateway的日志,接到的参数日志打出是这样的:

/xxxx/xxx/xxx/xxx接口名?xxxx=44A1BBD338B4467FC9733DE252DCAED0&xxxx={"xxxx":[{"xxxx":"test001","xxxx":"小明","xxxx":"test001@qq.com"}}]}

gateway这边接收到的是没问题的,所以nginx的配置是没有问题的,应该是gateway做了什么操作,debug发现:

在gateway这里如果请求的url里面有参数的话,会检查它是否都做过了urlencode,因为我的参数里面有一个复杂结构personList,所以在检查时报异常了,gateway认为url时没有urlencode的(实际上是编码了的),因此会再次进行编码,在编码后再传给目标服务的接口。

post请求使用url传参导致的线上事故_nginx

在服务的接口接收到参数时,框架本身会对参数进行一次decode,但由于gateway多做了一次encode,所以decode一次后还不够,需要再decode一次才行。

结论:代码要规范,post请求不用使用url传参,特别是有复杂结构时,使用body传参。

url传参就像这样:

POSThttp://xxxx.xxx.com.cn/xxx/xxx/xxxx?Identify=xxxx&BeginDate=2023-06-03 15:00:00&EndDate=2024-06-03 15:00:00&xxxx={"xxxx": [{"xxxx":"test001","xxx":"小明","xxxx":"xxxx@qq.com"}]}

很丑陋吧。

以上。