一次使用自定义 Http Header 引发的血案
起因
最近在整理我们产品的 OpenAPI Demo (Python、C#、Java),为使各语言 Demo 表现一致,使用同样的测试数据和同样的请求封装方式。
在 Python、C# 都特别顺利写完后,Java 遇到问题了:其中有一个接口返回 HTTP 400 错误,而其他接口都正常
环境
- JDK 1.8
- JAVA 调用接口使用 Apache HttpClient 4.2.1
排查
疑因1
由于 HTTP 400 Bad Request 很明显的是客户请求不满足服务端的要求,是客户端的问题,所以最先怀疑是客户端参数没传。
经过再三确认后,确认参数传递没有问题。
疑因2
排除疑因1后,有点陷入死局,不知如何下手。最后,有可能是请求通过 nginx 转发时,nginx 破坏了请求,导致应用服务器报 400.
于是,登录服务器,查看 Nginx 日志,发现请求没有被转发,如下图:
与正常的的请求相比,如下图:
未被转发的请求缺少了 Http Header : Host,也就是说错误的请求的 Host Header 被客户端丢弃,通过 Wireshark 抓包也确认是客户端的请求中没有 Host Header
疑因3
通过排除疑因2的过程,明确了问题出在请求调用方,而请求方式都是统一的封装接口,那么最有可能的原因就是请求的参数不一致导致。
于是,逐个去掉该请求的参数,发现其中一个 key 为 “productName”, value 为“测试修改产品名称” 的参数导致。将 value 改为其它值进行测试,发现没有问题,于是逐个去掉 value 的汉字,发现只要去掉“名”字就可测试通过。
这就奇了怪了,为什么有“名”字就测试不通过呢,又为什么其它语言能测试通过?!!!
思考。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
然后,对比有“名”字和无“名”字两次 wireshark 的抓包。
哇哇哇,为什么有“名”字的 Header 有换行
然后,将“名”字转换成 Unicode ,其值为 u540d
![ASCCI 转换 ASCCI 转换](./images/1533655474784.png)
然后对照 ASCCI 码表发现,发现 0D 表示“回车键”
![ASCCI 码表 ASCCI 码表](./images/1533654648952.png)
至此就清楚了,请求封装的代码将请求数据也放到了 Header ,而恰巧“名”字导致了 Header 头不合规范,从而导致 Host Header 丢失。而对比其它语言的请求封装类,并没有将请求数据放到 Header 中,这也解释了其它语言为什么可以测试通过。
经查 OpenAPI 的协议文档,并没有要求将请求数据放到 Header,而当时为什么这么做了,也无从考查。。。。。。
总结
虽然这次问题解决了,但却花费了半天的时间,在排查问题的时候,还是要再细心一些,多抓包并仔细分析,多对比正常情况与异常情况的不同,可能会事半功倍。
谨记!!!