使用httpclient返回 header too long
最近些的爬蟲請求某代理網站時運行幾天就會持續報錯400,header too long,google無答案,於是看了下源碼,主要原因為cookie的累積導致(可以理解為你的瀏覽器很久沒有清理緩存),以下為排查過程,解決方案見文章最後。
httclient請求調用鏈路:
org.apache.http.impl.client.InternalHttpClient#doExecute
org.apache.http.impl.client.InternalHttpClient#setupContext
if (context.getAttribute(HttpClientContext.COOKIE_STORE) == null) {
context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
}
如果沒有顯示設置cooki_store,取this(httpclient)的成員變數cookieStore,而通常我們httpClient只有1個實例,那麼cookieStore也等同於是單例的。
org.apache.http.impl.execchain.RedirectExec#execute:108
org.apache.http.impl.execchain.RetryExec#execute:86
org.apache.http.impl.execchain.ProtocolExec#execute
org.apache.http.impl.execchain.MainClientExec#execute
org.apache.http.protocol.HttpRequestExecutor#execute
conn.sendRequestHeader(request);
org.apache.http.protocol.HttpRequestExecutor#doSendRequest
org.apache.http.impl.conn.CPoolProxy#sendRequestHeader
org.apache.http.impl.io.AbstractMessageWriter#write
Cookie的發送:
for (final HeaderIterator it = message.headerIterator; it.hasNext; ) {
final Header header = it.nextHeader;
this.sessionBuffer.writeLine
(lineFormatter.formatHeader(this.lineBuf, header));
}
Cookie的保存:
org.apache.http.impl.execchain.ProtocolExec#execute:200
org.apache.http.HttpResponseInterceptor#process
org.apache.http.client.protocol.ResponseProcessCookies#process
org.apache.http.client.protocol.ResponseProcessCookies#processCookies:114
cookieStore.addCookie(cookie);
/**
* Adds an {@link Cookie HTTP cookie}, replacing any existing equivalent cookies.
* If the given cookie has already expired it will not be added, but existing
* values will still be removed.
*
* @param cookie the {@link Cookie cookie} to be added
*
* @see #addCookies(Cookie[])
*
*/
public synchronized void addCookie(final Cookie cookie) {
if (cookie != null) {
// first remove any old cookie that is equivalent
cookies.remove(cookie);
if (!cookie.isExpired(new Date)) {
cookies.add(cookie);
}
}
}
注意到這裡添加一個cookie時會先移除,然後判斷cookie是否已經失效,沒有失效才會add,這樣看是不會出問題的,那問題到底出在哪裡?而通過調試發現我們的第三方網站的sessionID的cookie的name居然是會變的!導致老的cookie無法刪除,越積越多。
解決方案①:禁用cookie
CloseableHttpClient httpClient = HttpClientBuilder.create.setConnectionManager(connManager)
.setRetryHandler(retryHandler).setDefaultRequestConfig(config).disableCookieManagement.build;
disableCookieManagement方法會停止發送和接收cookie。
/**
* Disables state (cookie) management.
*
* org.apache.http.protocol.HttpProcessor)} method.
*/
public final HttpClientBuilder disableCookieManagement {
this.cookieManagementDisabled = true;
return this;
}
啟用後org.apache.http.protocol.ImmutableHttpProcessor#responseInterceptors response攔截器里不再包含ResponseProcessCookies這一攔截器,不再執行存儲cookie操作,觀察後續請求,header里也不再包含cookie欄位。
攔截器註冊代碼:org.apache.http.impl.client.HttpClientBuilder#build:839
if (!cookieManagementDisabled) {
b.add(new RequestAddCookies);
}
if (!cookieManagementDisabled) {
b.add(new ResponseProcessCookies);
}
解放方案②:設置單獨的context
HttpClientContext context = HttpClientContext.create;
context.setCookieStore(new BasicCookieStore);
CloseableHttpResponse response = httpClient.execute(httpGet, context);
設置後因為context的cookieStore不為null,將不再默認取httpclient的成員變數cookiestore。
以上兩種方案,可根據自身情況進行選擇。
※對於所有對象都通用方法的解讀
※關於MySQL的commit非規律性失敗案例的深入分析
※Spark源碼閱讀之存儲體系--存儲體系概述與shuffle服務
※使用C創建WCF服務控制台應用程序
TAG:達人科技 |
※Iron Man 確定將於《Avengers: Endgame》太空中成功存活與返回地球?
※任天堂的Virtual Boy以非官方的Cardboard形式返回
※Andriod Q取消返回鍵 有點iPhone的味道
※Andriod Q取消返回鍵 有點iPhone的味道
※mybatis和Mysql返回插入的主鍵ID
※MyBatis 註解形式返回Map
※谷歌在Android Q Beta中嘗試新側滑返回手勢
※iPhone 8 Plus為什麼沒有輕觸返回功能?
※Switch Lite 發布,一加 7 Pro 加入側滑返回手勢
※從微博motan看rpc基於netty4遠程通訊設計4-同步非同步返回結果處理
※Windows漏洞利用開發教程Part 5:返回導向編程
※SpaceX載人龍飛船Crew Dragon成功完成首飛返回地球!
※SpaceX載人龍飛船Crew Dragon成功完成首飛返回地球
※Gigi Hadid 在紐約出街返回公寓
※Android Q 新系統將取消返回鍵?
※iphone8plus為什麼沒有輕觸返回功能?這才是關鍵
※XDA 開發者:Android Q 或取消返回鍵
※Spring MVC請求及返回JSON數據
※為啥 iPhone 沒有返回鍵?
※下一代 Android 或將取消 Home 鍵,但如何「返回」仍是個難題