最近发现线上服务器跑很久之后外部调用接口会出现Head too Long问题,重启后系统恢复正常,然后采用httppost.getAllHeaders打印出来的信息却为null~查看上一次构建项目的时间为2018-08-09,也就是距离出问题时间过去了18天~为什么一个应用前面18天一直正常,而在第18天会出现问题呢,这个问题引起了我们的怀疑。
首先我的httpClient并无对header进行多余的配置,和平常用法一样,我只是新建一个httpPost对象并调用execute()方法执行请求,而后,我这个execute方法有一个特点,就是我的项目所有post都是用了这个方法,但是只有这一个请求会报Bad Request(Request Header Too Long)或者Bad Request(Request Header Too Large)的问题,于是我开始一翻定位问题历程,开始猜想会不会是httpHeader里面的数据不断积压没释放导致的too Long呢, google一下发现资料相对比较少,
但httpHeader堆积的疑惑得到了进一步加深,查阅发现如果服务端在Cookie堆积的情况有可能导致此问题的出现,由于没有太多
的其他信息,而httpClient的版本又繁多,如org.apache.http3.X,4.X和org.eclipse.jetty.client.HttpClient等各种版本,于是开始
自己翻看当前所用的httpClient4.5.3的源码。我们用的httpClient的实现方式:
org.apache.http.impl.client.CloseableHttpClient.execute(HttpUriRequest)
上面的方法低层调用的是org.apache.http.impl.client.AbstartctHttpClient.doExecute(final HttpHost target, final HttpRequest request, final HttpContext context),如下图所示
经过源码查看发现COOKIE_STORE放在httpContext的attribute里面,于是开始了断点调试,断点调试发现在每次请求次Http接口时,COOK_STORE
的Name和Value数据不断增加,下面是调试数据
到这里,问题基本已经解决了,通常我们httpClient只有1个实例,那么cookieStore也等同于是单例的。通过调试发现我们的第三方网站的sessionID的cookie的name居然是会变的!
导致老的cookie无法删除,越积越多。如图~通过curl请求也会出现sessionID的name每次都变化的问题。
到此我们定位到了问题是由httpClient的默认httpContext里面的单例cookie_store不断堆积导致~那对应的改法就是每次都初始化httpContext,于是我们参照httpContext的源码,
采用每次创建都new 一个全新的CookieStore,至此,问题解决。目前已经成功见效。
org.apache.http.impl.client.AbstractHttpClient
参考源码后的改法:
日常的开发和处理问题的过程中,事无巨细 ,事必躬亲,我们要深刻的重视小问题、小bug反馈出来的一系列问题,举个例子,
针对这种18天才会出问题的bug,如果我们选择妥协即重启之后系统正常,或者因为这个问题是dev无法复现的问题,那我们选择
修改或者升级httpClient的版本等方案的话,最终不一定能够解决到我们的问题,或者说是治标不治本,但是如果我们选择敬畏问题,创
造条件,甚至挤出下班去挖掘问题的本质然后彻底解决问题的话,久而久之,我们也会变成别人眼中所羡慕的大神,我们的知识积
累也会慢慢加深,达到谦卑而有货,胸有成竹而不测漏。
事无巨细 事必躬亲