乐趣区

当年玩耍httpclient

当年玩耍 httpclient
前言
httpclient 是 java 开发中最常用的工具之一,通常大家会使用 httpcilent 去调用远程,使用其中比较基础的 api,长期开发爬虫,会接触 httpclient 不常用的 api,同时会遇到各式各样的坑,下面会总结这些年遇到的坑
坑坑坑
一:Received fatal alert: handshake_failure
解决过程
开发某省份移动爬虫时,加载首页会报标题错误,尝试各种办法都不好使,后来发现换了 jdk1.8 就好使经过长达一个星期源码探寻,发现错误源头是 http 在握手时,加密算法不支持导致 jdk1.8 以下版本不支持 256 位 (TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
解决方案
1、需要下载 jce 扩展包 http://www.oracle.com/technet…
2、替换 /jre/lib/security/ 里面的两个 jar
3、覆盖后如果报错 The jurisdiction policy files are not signed by a trusted signer!,
说明下载的版本不对,要下对应 jdk 版本的
二:Certificates does not conformto algorithm constraints
解决过程
用 mvn 打包时报错,security.cert.CertificateException: Certificates does not conform toalgorithm constraints 原因是在 java1.6 之后的这个配置文件中,认为 MD2 的加密方式安全性太低,因而不支持这种加密方式,同时也不支持 RSA 长度小于 1024 的密文需要修改 JAVA_HOME/jre/lib/security/java.security#jdk.certpath.disabledAlgorithms=MD2, RSA keySize < 1024
但是这样做需要把每台机器都改一遍,如果新加机器忘记改了,就会发生问题,需要一套方法,只在代码层解决问题
解决方案
经查源码发现了触发问题的代码位置,通过强制继承 SSLContextBuilder,并强制把 private 的 keymanagers 和 trustmanagers 的值置空就可以解决这个问题了
static class MySSLContextBuilder extends SSLContextBuilder {
static final String TLS = “TLS”;
static final String SSL = “SSL”;
private String protocol;
private Set<KeyManager> keymanagers;
private Set<TrustManager> trustmanagers;
private SecureRandom secureRandom;
public MySSLContextBuilder() {
super();
this.keymanagers = new HashSet<KeyManager>();
this.trustmanagers = new HashSet<TrustManager>();
}
}
三:超时时间不生效
解决过程
很多人在使用 httpclient 时会到网上去找例子,例子中经常会有类似这样的设置
httpGet.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, !isAutoRelocal);

使用上面方法时,发送 httpclient 时,在读取配置时如果发现 getParams 不为空,则会把以前设置的所有参数都不用了,而使用这里面设置的,所以超时时间会失效
解决方案
request.getParams().setParameter 是过期方法,其中每一项参数在 RequestConfig 里都有对应的,遍历出来替换一遍即可
boolean isRedirect = true;
if(request != null) {
HttpParams params = request.getParams();
if (params instanceof HttpParamsNames) {
// 暂时只支持这个类型
isRedirect = params.getBooleanParameter(
ClientPNames.HANDLE_REDIRECTS, true);
}
// 清空 request
request.setParams(new BasicHttpParams());
}
if(timeOut > 0) {
builder = RequestConfig.custom().setConnectionRequestTimeout(timeOut).setConnectTimeout(timeOut).setSocketTimeout(timeOut).setRedirectsEnabled(isRedirect).setCookieSpec(CookieSpecs.BEST_MATCH);
} else {
builder = RequestConfig.custom().setConnectionRequestTimeout(connectionTimeout).setConnectTimeout(connectionTimeout).setRedirectsEnabled(isRedirect).setSocketTimeout(socketTimeout).setCookieSpec(CookieSpecs.BEST_MATCH);
}
四:fildder 监听问题
问题
开发爬虫经常会使用 fildder 来监控网络请求,但是使用 httpclient 时想用 fildder 会很难,网上查各种办法,经常都不好使,下面为大家来排个错,使用下面方法就可以完美解决这个问题,让 fildder 监控更容易
解决方案
首先 java 端
// client builder
HttpClientBuilder builder = HttpClients.custom();
if(useFidder) {
// 默认 fidder 写死
builder.setProxy(new HttpHost(“127.0.0.1”, 8888));
}
fildder 端
tools->fiddler options->https->actions->export root certificate to …
<JDK_Home>\bin\keytool.exe -import -file C:\Users\<Username>\Desktop\FiddlerRoot.cer -keystore FiddlerKeystore -alias Fiddler
五:支持 gzip
问题及方案
有些网站返回进行了 gzip 压缩,返回内容是压缩的结果,需要解压

HttpClient wrappedHttpClient = builder.setUserAgent(requestUA)
.addInterceptorLast(new HttpResponseInterceptor() {
@Override
public void process(HttpResponse httpResponse, HttpContext httpContext) throws HttpException, IOException {
HttpEntity httpEntity = httpResponse.getEntity();
Header header = httpEntity.getContentEncoding();
if (header != null) {
for (HeaderElement element : header.getElements()) {
if (“gzip”.equalsIgnoreCase(element.getName())) {
httpResponse.setEntity(new GzipDecompressingEntity(httpResponse.getEntity()));
}
}
}
}
})
总结
上面一些能想起来的坑,还会遇到很多问题,欢迎来讨论
做一个广告:想简单开发爬虫的欢迎使用 uncs
作者:刘鹏飞 宜信技术学院

退出移动版