我们基础架构是用的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的(实际上是编码了的),因此会再次进行编码,在编码后再传给目标服务的接口。
在服务的接口接收到参数时,框架本身会对参数进行一次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"}]}
很丑陋吧。
以上。