基于HttpClient 4.3的可访问自签名HTTPS站点的新版工具类

本文出处:http://blog.csdn.net/chaijunkun/article/details/40145685,转载请注明。由于本人不定期会整理相关博文,会对相应内容作出完善。因此强烈建议在原始出处查看此文。

HttpClient在当今Java应用中的位置越来越重要。从该项目的变迁过程我们不难发现,其已经从apache-commons众多的子项目中剥离,一跃成为如今的顶级项目,可见它的分量。然而随着项目的升级和架构的调整,很多以前常用的类和方法都已被打上了@Deprecated注解,作为一个有代码洁癖的程序猿,我们也有必要升级一下工具类,让代码更加整洁。

另外在项目中正好需要访问https协议的接口,而对应的服务器没有购买商业CA颁发的正式受信证书,只是做了个自签名(联想一下12306网站购票时提示的那个警告信息),默认情况下通过HttpClient访问会抛出异常,在本文中也给出了解决办法。

在HttpClient 4.x版本中引入了大量的构造器设计模式,很多的配置都不建议直接new出来,而且相关的API也有所改动,例如连接参数,以前是直接new出HttpConnectionParams对象后通过set方法逐一设置属性,现在有了构造器,可以通过如下方式进行构造:

ConnectionConfig.custom().setCharset(Charsets.toCharset(defaultEncoding)).build();

SocketConfig.custom().setSoTimeout(100000).build();

基本情况就是这样,接下来谈下如何使用新的HttpClient来访问自签名https接口。

参阅CSDN博主noodies代码,发现实现访问自签名https的要点就是建立一个自定义的SSLContext对象,该对象要有可以存储信任密钥的容器,还要有判断当前连接是否受信任的策略,以及在SSL连接工厂中取消对所有主机名的验证。他的代码将会在本文最后贴出来,以下代码均针对新HttpClient。

首先建立一个信任任何密钥的策略。代码很简单,不去考虑证书链和授权类型,均认为是受信任的:

class AnyTrustStrategy implements TrustStrategy{

	@Override
	public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
		return true;
	}

}

HttpClient既能处理常规http协议,又能支持https,根源在于在连接管理器中注册了不同的连接创建工厂。当访问url的schema为http时,调用明文连接套节工厂来建立连接;当访问url的schema为https时,调用SSL连接套接字工厂来建立连接。对于http的连接我们不做修改,只针对使用SSL的https连接来进行自定义:

RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.<ConnectionSocketFactory>create();
ConnectionSocketFactory plainSF = new PlainConnectionSocketFactory();
registryBuilder.register("http", plainSF);
//指定信任密钥存储对象和连接套接字工厂
try {
	KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
	SSLContext sslContext = SSLContexts.custom().useTLS().loadTrustMaterial(trustStore, new AnyTrustStrategy()).build();
	LayeredConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
	registryBuilder.register("https", sslSF);
} catch (KeyStoreException e) {
	throw new RuntimeException(e);
} catch (KeyManagementException e) {
	throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
	throw new RuntimeException(e);
}
Registry<ConnectionSocketFactory> registry = registryBuilder.build();

在上述代码中可以看到,首先建立了一个密钥存储容器,随后让SSLContext开启TLS,并将密钥存储容器和信任任何主机的策略加载到该上下文中。构造SSL连接工厂时,将自定义的上下文和允许任何主机名通过校验的指令一并传入。最后将这样一个自定义的SSL连接工厂注册到https协议上。

前期准备已经完成,接下来我们要获得HttpClient对象:

//设置连接管理器
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry);
connManager.setDefaultConnectionConfig(connConfig);
connManager.setDefaultSocketConfig(socketConfig);
//构建客户端
HttpClient client= HttpClientBuilder.create().setConnectionManager(connManager).build();

为了让我们的HttpClient具有多线程处理的能力,连接管理器选用了PoolingHttpClientConnectionManager,将协议注册信息传入连接管理器,最后再次利用构造器的模式创建出我们需要的HttpClient。随后的GET/POST请求发起方法http和https之间没有差异。

为了验证我们的代码是否成功,可以做下JUnit单元测试:

@Test
public void doTest() throws ClientProtocolException, URISyntaxException, IOException{
	HttpUtil util = HttpUtil.getInstance();
	InputStream in = util.doGet("https://kyfw.12306.cn/otn/leftTicket/init");
	String retVal = HttpUtil.readStream(in, HttpUtil.defaultEncoding);
	System.out.println(retVal);
}

执行后可以在控制台看到12306余票查询界面的html代码

为了方便大家使用,本人将封装好的代码上传到了CSDN资源共享中,欢迎下载。

下载地址:http://download.csdn.net/detail/chaijunkun/8046331

最后感谢CSDN博主noodies的代码提供了思路:http://blog.csdn.net/noodies/article/details/17240805

本文中的部分代码参阅了HttpClient 4.3.5官方文档的2.7节关于Connection socket factories的内容

时间: 2025-01-02 17:00:38

基于HttpClient 4.3的可访问自签名HTTPS站点的新版工具类的相关文章

基于HttpClient 4.3的可訪问自签名HTTPS网站的新版工具类

本文出处:http://blog.csdn.net/chaijunkun/article/details/40145685,转载请注明.因为本人不定期会整理相关博文,会对相应内容作出完好.因此强烈建议在原始出处查看此文. HttpClient在当今Java应用中的位置越来越重要.从该项目的变迁过程我们不难发现,其已经从apache-commons众多的子项目中剥离,一跃成为现在的顶级项目.可见它的分量.然而随着项目的升级和架构的调整.非常多曾经经常使用的类和方法都已被打上了@Deprecated

HTTPS的证书未经权威机构认证的情况下,访问HTTPS站点的两种方法

注意一下文章中提到的jsse在jdk1.4以后已经集成了,不必纠结. 摘 要 JSSE是一个SSL和TLS的纯Java实现,通过JSSE可以很容易地编程实现对HTTPS站点的访问.但是,如果该站点的证书未经权威机构的验证,JSSE将拒绝信任该证书从而不能访问HTTPS站点.本文在简要介绍JSSE的基础上提出了两种解决该问题的方法. 引言 过去的十几年,网络上已经积累了大量的Web应用.如今,无论是整合原有的Web应用系统,还是进行新的Web开发,都要求通过编程来访问某些Web页面.传统的方法是使

Android开发之网络请求通信专题(二):基于HttpClient的文件上传下载

上一篇专题Android开发之网络请求通信专题(一):基于HttpURLConnection的请求通信我们讲解了如何使用httpurlconnection来实现基本的文本数据传输.一般在实际开发中我们可以用于传输xml或者json格式的数据.今天我们来讲解另外一种http网络请求的方式:httpclient,并实现文件的上传和下载. 在这里插个题外话,其实这些网络请求有很多第三方jar包可以使用,这些包都封装得很好了.如果只是想使用,我们就直接拿别人得jar包来用就好.博主这里推荐一个叫xuti

安卓实训第四天--基于HttpClient来完成数据在服务器和设备间的交互。

上午:老师首先回顾了昨天作业. 首先在安卓工程中的TOOLS文件中,解析字节流那里,不用改变,而是把服务器端的编码方式变为UTF-8,然后将在安卓工程的LoginActivity类中的USERNAME给他强制转换下. 总结一句话:如果一个字符通过某个编码转换成字节码之后,那你在转换的时候必须拿到转换之前的字节码 补充:如何改变mysql连接工具的编码方式: jdbc:mysql://localhost:3306/databasename?useUnicode=true&characterEnco

Apache HttpClient访问网络工具类

1 package com.ztravel.utils; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org

基于CORS的GeoServer跨域访问策略

GeoServer的跨域访问问题,有多种解决方法,本文介绍一种基于CORS的GeoServer跨域访问方法. CORS简介 CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing). CORS是一种允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本请求访问的机制,它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制.通常由于同域

基于HttpClient的新版正方教务系统模拟登录及信息获取API

简介 通过HttpClient获取网页数据源,通过Jsoup解析数据.先模拟登录,再获取信息.模拟浏览器正常操作,封装请求头信息获取SESSIONID.模拟登录成功后切勿断开会话,依赖登录请求得到的Cookie进行二次请求.请求信息时需打开谷歌浏览器或Fiddler抓包查看参数及请求头信息. Maven依赖 1 <dependency> 2 <groupId>com.baidu.aip</groupId> 3 <artifactId>java-sdk<

org.apache.httpcomponents:httpclient 工具类

基于httpclient 版本4.4.1 因为http连接需要三次握手,在需要频繁调用时浪费资源和时间 故采用连接池的方式连接 根据实际需要更改  连接池最大连接数.路由最大连接数 另一个需要注意的是 // 释放Socket流 response.close(); // 释放Connection // httpClient.close(); 1 import org.apache.http.HttpEntity; 2 import org.apache.http.NameValuePair; 3

轻松把玩HttpClient之封装HttpClient工具类(三),插件式配置Header

上篇文章介绍了插件式配置HttpClient,本文将介绍插件式配置Header. 为什么要配置header在前面已经提到了,还里再简单说一下,要使用HttpClient模拟请求,去访问各种接口或者网站资源,都有可能有各种限制,比如说java客户端模拟访问csdn博客,就必须设置User-Agent,否则就报错了.还有各种其他情况,必须的设置一些特定的Header,才能请求成功,或者才能不出问题. 好了就说这么多,本次还是采用构造者模式的级联调用方式,来完成该工具类.在该工具类中,为所有常用的Ht