背景
由于公司出于安全考虑,准备统一收拢对外出口服务器,同时对出口请求进行监控管理,因此tplinker项目孕育而生
项目简介
该项目针对不同场景主要有两种模式
- 透传模式:主要用于兼容现有业务直接对外请求接口,该模式对于已经开发请求URL配置代理域名,请求先通过Nginx转发到出口服务器中,再经过tplinker出口服务,出入参直接透传。
- 非透传模式:主要用于对后续新对接出口接口,tplinker对接口涉及的加解签、加解密相关内容完成,因此业务侧只需要关心业务的开发。同时对外接口相关调用进行汇总统计监控。
遇到问题
在开发以及将历史出口URL统一收拢时遇到不少问题,在此和读者分享下,希望有所帮助
通过出口代理后签名错误
通过查看代码签名方式时,发现在进行生成签名的时候会将请求URL也作为参数与其他请求参数进行生成签名,而改方式是通过透传方式,该种方式会将配置的请求URL前加一个固定的例如:outgoing-gateway,NG识别到该域名会代理到目标tplinker服务中去,因此客户端URL是有加outgoing-gateway该值进行签名,而服务端使用约定好的参数进行签名是不带outgoing-gateway因此导致双方签名结果不一致。目前遇到会将请求URL也作为参数进行签名的场景好像是比较少的
解决:在进行加签时采用原生的URL进行生成签名,请求出去的时候再把代理域名加上
通过出口代理后接口403无权限
这个问题当时定位起来有些困难了,因为这个当时在Test、Uat环境都没问题可以正常访问,但是在生产环境接口403,很奇怪,这里就完全可以排除代码层面的问题。后续猜想是否是由于新的出口服务IP未在对方配置白名单所致?很快这种可能被我们否定,原因有二,一是我们公司内网出口IP会统一规整成固定的四个IP,因此我们出口IP对方一定是配置了IP白名单。在此问题陷入僵局…
后续通过查看NG日志比对发现,在Pord请求403时
X-Forwarded-For设置的是出口网关服务器的IP,查看NG配置发现Pord的NG有配置如下:proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 该段配置的意思是将客户端的真实IP设置在X-Forwarded-For之后,而Test环境的NG无该段配置,其取的默认就是出口的IP。问题就是发生在这里,我们猜测对方服务端是直接取的X-Forwarded-For作为真实IP去校验白名单的,但是!!!XFF请求头是可以伪造的,取该头中的IP去校验无法保证对方真实的IP是合法的。在后续,我们通过CURL命令在自己本地,通过伪造X-Forwarded-For中IP指定为IP白名单的IP发现能正常请求通,在此问题已经显山漏水了。
就是X-Forwarded-For请求头所致,因此在我们生产NG先去处了
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 配置后,发现确实能正常请求了。但是我们NG配置该值是应该的,是对方一味的相信外部传入的XFF配置。经过我们提醒对方后,对方也发现了问题的所在并相应进行了调整。问题得解。
通过出口代理后接口No Response
查看NG发现结果响应:upstream sent invalid chunked response while reading upstream,通过字面意思解析当读取流时发现服务端发送的是无效的响应块,这里涉及到一个Chunked编码问题(Chunked编码简单来说就是将响应体拆分成N个块,统一发送给客户端,通过这种方式无需知道主体部分的大小,传输更加高效灵活,在到达接收方后再将这些快拼接起来形成完整的数据流),可以通过指定一下NG配置解决
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_http_version 1.1;:设置使用 HTTP 1.1 协议与代理服务器进行通信,默认值是 1.0。通过设置为 1.1,可以使用 chunked 编码方式传输数据,提高数据传输效率。proxy_set_header Connection "";:设置请求头中的 Connection 字段为空。这是为了避免客户端使用 keep-alive 长连接方式与 Nginx 保持连接,在经过代理服务器时,产生奇怪的问题,如出现“upstream sent invalid chunked response while reading upstream”错误。
通过出口网关后部分请求空响应
接入网关后,偶现响应体为空的情况。原因:调用的httpclient使用了长连接,客户端的长连接保持时间过长,而服务端会定时去清除不常使用的长连接,而此时客户端无法得知服务端已经将该连接清除,继续使用该连接发请求因此无响应。
后记
在此记录下项目中遇到的问题,如果不对之处还请指教!