那些年用httpclient时踩过的一些坑
一、前言
httpclient是java开发中最常用的工具之一,通常大家会使用其中比较基础的api去调用远程。长期开发爬虫,会接触httpclient不常用的api,同时会遇到各式各样的坑,本文将总结这些年遇到的坑及相应的解决方案。
二、问题及解决方案
问题1:Receivedfatalalert: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、覆盖后如果报错Thejurisdictionpolicyfilesarenotsignedbyatrustedsigner!,说明下载的版本不对,要下对应jdk版本的。
问题2:Certificatesdoesnotconformtoalgorithmconstraints
问题背景
用mvn打包时报错,security.cert.CertificateException:Certificatesdoesnotconformtoalgorithmconstraints
原因是在java1.6之后的这个配置文件中,认为MD2的加密方式安全性太低,因而不支持这种加密方式,同时也不支持RSA长度小于1024的密文。
需要修改JAVA_HOME/jre/lib/security/java.security#jdk.certpath.disabledAlgorithms=MD2,RSAkeySize<1024
但是这样做需要把每台机器都改一遍,如果新加机器忘记改了,就会继续报错。因此需要一套方法,只在代码层解决问题。
解决方案
经查源码发现了触发问题的代码位置,通过强制继承SSLContextBuilder,并强制把private的keymanagers和trustmanagers的值置空就可以解决这个问题了。
代码如下:
staticclassMySSLContextBuilderextendsSSLContextBuilder{
staticfinalStringTLS="TLS";
staticfinalStringSSL="SSL";
privateStringprotocol;
privateSetkeymanagers;
privateSettrustmanagers;
privateSecureRandomsecureRandom;
publicMySSLContextBuilder(){
super();
this.keymanagers=newHashSet();
this.trustmanagers=newHashSet();
}
}
问题3:超时时间不生效
问题背景
很多人在使用httpclient时会到网上去找例子,例子中经常会有类似这样的设置
httpGet.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS,!isAutoRelocal);
使用上述方法发送httpclient,在读取配置时,如果发现getParams不为空,则会使得以前设置的所有参数都失效,而使用这里设置的,结果是导致超时时间失效。
解决方案
request.getParams().setParameter是过期方法,其中每一项参数在RequestConfig里都有对应的,遍历出来替换一遍即可。
booleanisRedirect=true;
if(request!=null){
HttpParamsparams=request.getParams();
if(paramsinstanceofHttpParamsNames){
//暂时只支持这个类型
isRedirect=params.getBooleanParameter(
ClientPNames.HANDLE_REDIRECTS,true);
}
//清空request
request.setParams(newBasicHttpParams());
}
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端
//clientbuilder
HttpClientBuilderbuilder=HttpClients.custom();
if(useFidder){
//默认fidder写死
builder.setProxy(newHttpHost("127.0.0.1",8888));
}
fildder端
tools->fiddleroptions->https->actions->exportrootcertificateto...\bin\keytool.exe-import-fileC:\Users\\Desktop\FiddlerRoot.cer-keystoreFiddlerKeystore-aliasFiddler
问题5:支持gzip
问题及解决方案
有些网站返回进行了gzip压缩,返回内容是压缩的结果,需要解压。
代码如下:
HttpClientwrappedHttpClient=builder.setUserAgent(requestUA)
.addInterceptorLast(newHttpResponseInterceptor(){
@Override
publicvoidprocess(HttpResponsehttpResponse,HttpContexthttpContext)throwsHttpException,IOException{
HttpEntityhttpEntity=httpResponse.getEntity();
Headerheader=httpEntity.getContentEncoding();
if(header!=null){
for(HeaderElementelement:header.getElements()){
if("gzip".equalsIgnoreCase(element.getName())){
httpResponse.setEntity(newGzipDecompressingEntity(httpResponse.getEntity()));
}
}
}
}
})
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对毛票票的支持。