今天服务里的微信公众号支付业务忽然不能用了,报错为网络环境未能经过安全验证,请稍后再试。检查后端日志,没有任何问题,看来是成功建立支付订单,可是调起支付时出现了问题。上网查了一下,这个报错的直接缘由是传入的客户端ip与调起支付的ip不符。可是印象中我在代码中获取的是X-Forwarded-For,就是请求来源的客户端IP,就查看日志发现传给微信的ip为172.17.0.1,也就是宿主机ip,这是才恍然大悟,在升级线上环境时咱们将全部服务放进了docker,而且在docker里装了nginx来分发请求给对应的服务,也就是说咱们是两级nginx代理,咱们的服务是无法拿到最外层客户端ip的。只好改进nginx将每级代理的ip都记录起来,而不是直接覆盖。nginx
改进方法:docker
对第一级nginx代理后端
location ~ ^/test {
proxy_pass http://127.0.0.1:8888;
proxy_set_header Host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
}安全
第一级nginx代理不须要改动,直接将原始客户端ip记录到X-Forwarded-For便可微信
对于第二级,以及以后可能存在的更多级代理网络
location ~ ^/test {
proxy_pass http://127.0.0.1:12000;
proxy_set_header Host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}spa
这样就将新一级代理的ip接到X-Forwarded-For的尾部,并用逗号分割。也就是说X-Forwarded-For是一个逗号拼接的ip字符串,想拿到原始ip只须要按逗号分割,取第一位ip便可。代理
Golang业务中读取原始客户端ip代码日志
real_ip := r.Header.Get("X-Forwarded-For") ip_list := strings.Split(real_ip, ",") if len(ip_list) > 1 { real_ip = ip_list[0] }
就是这么简单啦,但愿对你们有所帮助~blog