您的位置:首页 > 职场人生

程序员笔记|当年用httpclient时踩过的那些坑

2019-05-15 18:05 1196 查看

【技术沙龙002期】数据中台:宜信敏捷数据中台建设实践|宜信技术沙龙 将于5月23日晚8点线上直播,点击报名

一、前言

httpclient是java开发中最常用的工具之一,通常大家会使用其中比较基础的api去调用远程。长期开发爬虫,会接触httpclient不常用的api,同时会遇到各式各样的坑,本文将总结这些年遇到的坑及相应的解决方案。

二、问题及解决方案

问题1: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/technetwork/cn/java/javase/downloads/jce-7-download-432124.html

2、替换/jre/lib/security/里面的两个jar

3、覆盖后如果报错The jurisdiction policy files are not signed by a trusted signer!,说明下载的版本不对,要下对应jdk版本的。

问题2: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 keymanagers;
private Set trustmanagers;
private SecureRandom secureRandom;
public MySSLContextBuilder() {
super();
this.keymanagers = new HashSet();
this.trustmanagers = new HashSet();
}
}

问题3:超时时间不生效

问题背景

很多人在使用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);
}

问题4: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 ... \bin\keytool.exe -import -file C:\Users\\Desktop\FiddlerRoot.cer -keystore FiddlerKeystore -alias Fiddler

问题5:支持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()));
}
}
}
}
})

作者:刘鹏飞

来源:宜信技术学院

(adsbygoogle = window.adsbygoogle || []).push({});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  HttpClient