最近些的爬虫请求某代理网站时运行几天就会持续报错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.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. * <p/> * Please note this value can be overridden by the {@link #setHttpProcessor( * 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。
以上两种方案,可根据自身情况进行选择。
相关推荐
httpclient的用法,发送get请求和post请求,设置header
使用HttpClient必须的jar包 使用HttpClient必须的jar包 使用HttpClient必须的jar包
try(CloseableHttpClient httpClient = HttpClients.createDefault()) { HttpPost httpPost = new HttpPost(url); StringEntity stringEntity = new StringEntity(params, Charset.forName("UTF-8")); ...
HttpClient是个很不错的开源框架(org.appache.http),封装了访问http的请求头,参数,内容体,响应等等,使用起来更方面更强大。 HttpURLConnection是java的标准类,可以实现简单的基于URL请求、响应功能,什么都...
一个使用HttpClient调用接口的例程,接口是从网上找来的,只支持get方式提交,返回json格式,此例程的编码方式为GBK,我写了注释
使用HttpClient登录网易邮箱 博文链接:https://bps.iteye.com/blog/136231
NULL 博文链接:https://goro.iteye.com/blog/1636275
commons-httpclient,java中使用httpclient中使用的扩展工具
使用 HttpClient 和 HtmlParser 实现简易网络爬虫
使用HttpClient获取网页html源代码获取到的源码不解析直接显示,技术比较简单,需要的朋友可以下载研究一下,项目编码GBK默认编译版本2.3.3。
Http协议使用封装jar包(commons-codec-1.3.jar、commons-httpclient-3.1.jar、commons-logging-1.1.jar) 简单使用方法: public static void main(String[] args) { // String str1 = "...
Android 使用HttpClient代理
commons-httpclient-3.0.jar JAVA中使用HttpClient可以用到
Android Studio使用HttpClient请求数据(get请求)不包括post请求
一个使用HttpClient访问WS 的例子,包含相关jar包
http://jakarta.apache.org/commons/httpclient/ org.apache.commons.httpclient.URI org.apache.commons.httpclient.Wire org.apache.commons.httpclient.Cookie org.apache.commons.httpclient.Header org.apache....
HttpClient与Asynctask与服务器的结合使用
Eclipse下完整的java程序,包含HttpClient的全部jar包。通过java类文件,实现通过链接将文件下载本地
我使用的是httpClient 进行内部转发 我们在A的服务器上,将前台的文件流,通过httpClient传输到B的服务器上(B的服务器通过控制层接受A传输的文件流,让后保存在B的服务器上。返回一个json结果)