HttpClient 4.3中Https的使用方法
开发Android版Do+新浪微博客户端时使用到了HTTPClient库,当时刚刚接触API接口开发很多都不懂,直接调用HTTPS时直接报证书错误,后来查找资料发现,HTTPClient在请求HTTPS时也需要证书认证。通过自定义HTTPClient顺利实现了接口调用。最近在做另外一个项目,也会通过HTTPClient来调用第三方的API,所以又查看了一下HTTPClient的源码,把HTTPS的请求方式重新梳理一下。
注意:Android项目中内嵌的HTTPClient库版本为4.2.3,详见此处。下面介绍中使用的库为4.3,两者之间有些差异。4.3当前为开发版,谨慎使用。
以新浪微博API为例,
1、通过浏览器下载https://api.weibo.com的证书
Chrome浏览器,地址栏中键入“https://api.weibo.com/oauth2/authorize”,点击左侧绿色锁状图标,选择"连接"选项卡,点击"证书信息"
IE浏览器,地址栏中键入“https://api.weibo.com/oauth2/authorize”,点击右侧橙色锁状图标,点击"查看证书信息"
弹出对话框,选择“详细信息”选项卡,右侧点击“复制到文件”,进入证书导出向导,点击"下一步",选择"Base64 编码 X.509(.CER)(S)",点击"下一步",选择证书保存位置。证书导出成功。
2、加载证书信息,构造KeyStore。默认将证书.cer放在src下
// 从InputStream加载CA证书
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = this.getClass().getClassLoader().getResourceAsStream("doubanapi.cer");
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
// System.out.println("ca=" + ((X509Certificate)ca).getSubjectDN());
} finally {
caInput.close();
}
//构造含有信任CA证书的KeyStore
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
trustStore.setCertificateEntry("ca", ca);
3、构造SSLContext
// SSLContext
SSLContextBuilder sslContextbuilder = new SSLContextBuilder();
sslContextbuilder.useTLS();
sslContextbuilder.loadTrustMaterial(trustStore);
4、创建可用Scheme
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
.<ConnectionSocketFactory> create()
.register("http", PlainSocketFactory.INSTANCE)
.register("https",new SSLSocketFactory(sslContextbuilder.build(),SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)).build();
5、创建ConnectionManager,添加Connection配置信息
// ConnectionManager
PoolingHttpClientConnectionManager conManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
MessageConstraints messageConstraints = MessageConstraints.custom().setMaxHeaderCount(200).setMaxLineLength(2000).build();
//ConnectionConfig
ConnectionConfig connectionConfig = ConnectionConfig.custom()
.setMalformedInputAction(CodingErrorAction.IGNORE)
.setUnmappableInputAction(CodingErrorAction.IGNORE).setCharset(Consts.UTF_8)
.setMessageConstraints(messageConstraints).build();
conManager.setDefaultConnectionConfig(connectionConfig);
6、构建HTTPClient
HttpClients.custom().setConnectionManager(conManager).build();
7、发起HTTP Request
HttpPost requestP = new HttpPost(url);
// params
if (params != null) {
List<NameValuePair> pm = new ArrayList<NameValuePair>();
Iterator<Entry<String, Object>> iterator = params.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Object> entry = (Map.Entry<String, Object>) iterator.next();
pm.add(new BasicNameValuePair(entry.getKey(), To.toString(entry.getValue())));
}
requestP.setEntity(new UrlEncodedFormEntity(pm, Consts.UTF_8));
}
// header
if (header != null) {
Iterator<Entry<String, String>> iterator = header.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = (Map.Entry<String, String>) iterator.next();
requestP.setHeader(entry.getKey(), entry.getValue());
}
}
HttpResponse response = new XHttpClient().getHttpClient().execute(requestP);
String content = EntityUtils.toString(response.getEntity()));
return response.getStatusLine().getStatusCode();
8、当前默认编码为UTF-8.在之前版本中设置编码是通过BasicParam设置为HTTP.UTF-8
在新版本中改为Config模式,参数为Consts.UTF-8。