【技术沙龙002期】数据中台:宜信敏捷数据中台建设实践|宜信技术沙龙 将于5月23日晚8点线上直播,点击报名html
httpclient是java开发中最经常使用的工具之一,一般你们会使用其中比较基础的api去调用远程。长期开发爬虫,会接触httpclient不经常使用的api,同时会遇到各式各样的坑,本文将总结这些年遇到的坑及相应的解决方案。java
问题1:Received fatal alert: handshake_failure算法
问题背景api
开发某省份移动爬虫时,加载首页会报标题错误,尝试各类办法都很差使,后来发现换了jdk1.8就能够了。通过长达一个星期源码探寻,发现错误源头是http在握手时,加密算法不支持。安全
jdk1.8如下版本不支持256位(TLS_DHE_RSA_WITH_AES_256_CBC_SHA )网络
解决方案oracle
一、下载jce扩展包 http://www.oracle.com/technetwork/cn/java/javase/downloads/jce-7-download-432124.htmlapp
二、替换/jre/lib/security/里面的两个jardom
三、覆盖后若是报错The jurisdiction policy files are not signed by a trusted signer!,说明下载的版本不对,要下对应jdk版本的。socket
问题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())); } } } } })
做者:刘鹏飞
来源:宜信技术学院