上幾篇文章我們談到fastweixin使用問題和修改。
今天的問題就是使用JAVA訪問HTTPS網站時候經常出現javax.net.ssl.SSLHandshakeException
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(Unknown Source)
對於這個問題,一般採用兩種方法:1、導入疼訊網站證書 2、修改代碼
考慮到很多人的服務器並不是自主控制,無法進行第一種方法,導入證書,下面決定修改原框架代碼以便適應HTTPS。
package com.fastwixinextend;
import com.github.sd4324530.fastweixin.util.NetWorkCenter;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import javax.net.ssl.SSLContext;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* com.github.sd4324530.fastweixin.util.NetWorkCenter 修改版本
* http://blog.csdn.net/xiaoxian8023/article/details/49865335
*
* 將 com.github.sd4324530.fastweixin.util修改 public final class NetWorkCenter
* extends MyNetWorkCenter {
*
* 採用https的訪問協議獲取新的AccessToken時,總是出現異常: javax.net.ssl.SSLHandshakeException:
* sun.security.validator.ValidatorException: PKIX path building failed:
* sun.security.provider.certpath.SunCertPathBuilderException: unable to find
* valid certification path to requested target 之後在網上找了很多例子,最後摘了一個不需要證書的例子:
*/
public class MyNetWorkCenter {
/**
* 默認連接超時時間(毫秒) 由於目前的設計原因,該變量定義爲靜態的,超時時間不能針對每一次的請求做定製 備選優化方案:
* 1.考慮是否重新設計這個工具類,每次請求都需要創建一個實例; 2.請求方法里加入超時時間參數
* 或者說是否沒必要定製,10秒是一個比較適中的選擇,但有些請求可能就是需要快速給出結果T_T
*/
public static final int CONNECT_TIMEOUT = 10 * 1000;
private static final Logger LOG
= LoggerFactory.getLogger(NetWorkCenter.class);
private static final Charset UTF_8 = Charset.forName("UTF-8");
public MyNetWorkCenter() {
super();
}
/**
* 自定義HTTP響應回調接口,用於兼容jdk6
*
* @author peiyu
* @since 1.1
*/
// @FunctionalInterface
public interface ResponseCallback {
/**
* 響應後回調方法
*
* @param resultCode 響應結果碼,比如200成功,404不存在,500服務器異常等
* @param resultJson 響應內容,目前支持JSON字符串
*/
void onResponse(int resultCode, String resultJson);
}
/**
* 標識HTTP請求類型枚舉
*
* @author peiyu
* @since 1.0
*/
public enum RequestMethod {
/**
* HTTP GET請求 一般對應的是查詢業務接口
*/
GET,
/**
* HTTP POST請求 一般對應的是新增業務接口 只是一般都通用這個請求方式來處理一切接口了T_T
*/
POST,
/**
* HTTP PUT請求,用的太少,暫不支持 一般對應的是更新業務接口
*/
PUT,
/**
* HTTP DELETE請求,用的太少,暫不支持 一般對應的是刪除業務接口
*/
DELETE;
private static final long serialVersionUID = 1L;
}
/**
* 處理HTTP請求 基於org.apache.http.client包做了簡單的二次封裝 對於子函數,修改doRequest() String
* ishttp=url.toLowerCase(); if(ishttp.startsWith("https") ||
* ishttp.startsWith("HTTPS")) { doRequestSSH(method, url, paramData,
* fileList, callback); return; }
*
* @param method HTTP請求類型
* @param url 請求對應的URL地址
* @param paramData 請求所帶參數,目前支持JSON格式的參數
* @param fileList 需要一起發送的文件列表
* @param callback
* 請求收到響應後回調函數,參數有2個,第一個爲resultCode,即響應碼,比如200爲成功,404爲不存在,500爲服務器發生錯誤;
* 第二個爲resultJson,即響應回來的數據報文
*/
public static void doRequestSSH(final RequestMethod method, final String url,
final String paramData,
final List<File> fileList,
final ResponseCallback callback) {
//如果url沒有傳入,則直接返回
if (null == url || url.isEmpty()) {
LOG.warn("The url is null or empty!!You must give it to me!OK?");
return;
}
//默認期望調用者傳入callback函數
boolean haveCallback = true;
/*
* 支持不傳回調函數,只輸出一個警告,並改變haveCallback標識
* 用於一些不需要後續處理的請求,比如只是發送一個心跳包等等
*/
if (null == callback) {
LOG.warn("--------------no callback block!--------------");
haveCallback = false;
}
LOG.debug("-----------------請求地址:{}-----------------", url);
//配置請求參數
RequestConfig config
= RequestConfig.custom().setConnectionRequestTimeout(CONNECT_TIMEOUT).setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(CONNECT_TIMEOUT).build();
SSLContext sslcontext = null;
// 設置協議http和https對應的處理socket鏈接工廠的對象
try {
sslcontext = SslUtils.createIgnoreVerifySSL();
} catch (KeyManagementException e) {
} catch (NoSuchAlgorithmException e) {
}
Registry<ConnectionSocketFactory> socketFactoryRegistry
= RegistryBuilder.<ConnectionSocketFactory>create().register("http",
PlainConnectionSocketFactory.INSTANCE).register("https",
new SSLConnectionSocketFactory(sslcontext)).build();
PoolingHttpClientConnectionManager connManager
= new PoolingHttpClientConnectionManager(socketFactoryRegistry);
HttpClients.custom().setConnectionManager(connManager);
//創建自定義的httpclient對象
HttpClientBuilder HttpClientbuilder = HttpClients.custom().setConnectionManager(connManager);
HttpClientbuilder.setDefaultRequestConfig(config);
CloseableHttpClient client = HttpClientbuilder.build();
//CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
HttpUriRequest request = null;
switch (method) {
case GET:
String getUrl = url;
if (null != paramData) {
getUrl += "?" + paramData;
}
request = new HttpGet(getUrl);
break;
case POST:
LOG.debug("請求入參:");
LOG.debug(paramData);
request = new HttpPost(url);
//上傳文件
if (null != fileList && !fileList.isEmpty()) {
LOG.debug("上傳文件...");
MultipartEntityBuilder builder
= MultipartEntityBuilder.create();
for (File file : fileList) {
//只能上傳文件哦 ^_^
if (file.isFile()) {
FileBody fb = new FileBody(file);
builder.addPart("media", fb);
} else { //如果上傳內容有不是文件的,則不發起本次請求
LOG.warn("The target '{}' not a file,please check and try again!",
file.getPath());
return;
}
}
if (null != paramData) {
builder.addPart("description",
new StringBody(paramData, ContentType.APPLICATION_JSON));
}
((HttpPost) request).setEntity(builder.build());
} else //不上傳文件的普通請求
{
if (null != paramData) {
// 目前支持JSON格式的數據
StringEntity jsonEntity
= new StringEntity(paramData, ContentType.APPLICATION_JSON);
((HttpPost) request).setEntity(jsonEntity);
}
}
break;
case PUT:
case DELETE:
default:
LOG.warn("-----------------請求類型:{} 暫不支持-----------------",
method.toString());
break;
}
CloseableHttpResponse response = null;
try {
URL u = new URL(url);
if ("https".equalsIgnoreCase(u.getProtocol())) {
SslUtils.ignoreSsl();
}
long start = System.currentTimeMillis();
//發起請求
response = client.execute(request);
long time = System.currentTimeMillis() - start;
LOG.debug("本次請求'{}'耗時:{}ms",
url.substring(url.lastIndexOf("/") + 1, url.length()),
time);
int resultCode = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
//此流不是操作系統資源,不用關閉,ByteArrayOutputStream源碼裏close也是個空方法-0_0-
// OutputStream os = new ByteArrayOutputStream();
// entity.writeTo(os);
// String resultJson = os.toString();
String resultJson = EntityUtils.toString(entity, UTF_8);
//返回碼200,請求成功;其他情況都爲請求出現錯誤
if (HttpStatus.SC_OK == resultCode) {
LOG.debug("-----------------請求成功-----------------");
LOG.debug("響應結果:");
LOG.debug(resultJson);
if (haveCallback) {
callback.onResponse(resultCode, resultJson);
}
} else if (haveCallback) {
LOG.warn("-----------------請求出現錯誤,錯誤碼:{}-----------------",
resultCode);
callback.onResponse(resultCode, resultJson);
}
} catch (ClientProtocolException e) {
LOG.error("ClientProtocolException:", e);
LOG.warn("-----------------請求出現異常:{}-----------------",
e.toString());
if (haveCallback) {
callback.onResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR,
e.toString());
}
} catch (IOException e) {
LOG.error("IOException:", e);
LOG.warn("-----------------請求出現IO異常:{}-----------------",
e.toString());
if (haveCallback) {
callback.onResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR,
e.toString());
}
} catch (Exception e) {
LOG.error("Exception:", e);
LOG.warn("-----------------請求出現其他異常:{}-----------------",
e.toString());
if (haveCallback) {
callback.onResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR,
e.toString());
}
} finally {
//abort the request
if (null != request && !request.isAborted()) {
request.abort();
}
//close the connection
HttpClientUtils.closeQuietly(client);
HttpClientUtils.closeQuietly(response);
}
}
}
原文件NetWorkCenter 修改如下:
package com.github.sd4324530.fastweixin.util;
import com.fastwixinextend.MyNetWorkCenter.RequestMethod;
import com.fastwixinextend.MyNetWorkCenter.ResponseCallback;
import com.github.sd4324530.fastweixin.api.response.BaseResponse;
import com.fastwixinextend.MyNetWorkCenter;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
/**
* HTTP請求客戶端操作類,基於org.apache.http.client包4.4.x版本實現
*/
public final class NetWorkCenter extends MyNetWorkCenter {
/**
* 默認連接超時時間(毫秒) 由於目前的設計原因,該變量定義爲靜態的,超時時間不能針對每一次的請求做定製 備選優化方案:
* 1.考慮是否重新設計這個工具類,每次請求都需要創建一個實例; 2.請求方法里加入超時時間參數
* 或者說是否沒必要定製,10秒是一個比較適中的選擇,但有些請求可能就是需要快速給出結果T_T
*/
public static final int CONNECT_TIMEOUT = 10 * 1000;
/**
* 日誌輸出組件
*/
private static final Logger LOG = LoggerFactory.getLogger(NetWorkCenter.class);
private static final Charset UTF_8 = Charset.forName("UTF-8");
/**
* 私有化構造器 不允許外界創建實例
*/
private NetWorkCenter() {
LOG.warn("Oh,my god!!!How do you call this method?!");
LOG.warn("You shouldn't create me!!!");
LOG.warn("Look my doc again!!!");
}
/**
* 發起HTTP POST同步請求 jdk8使用函數式方式處理請求結果 jdk6使用內部類方式處理請求結果
*
* @param url 請求對應的URL地址
* @param paramData 請求所帶參數,目前支持JSON格式的參數
* @param callback
* 請求收到響應後回調函數,參數有2個,第一個爲resultCode,即響應碼,比如200爲成功,404爲不存在,500爲服務器發生錯誤;
* 第二個爲resultJson,即響應回來的數據報文
*/
public static void post(String url, String paramData,
ResponseCallback callback) {
post(url, paramData, null, callback);
}
public static BaseResponse post(String url, String paramData) {
final BaseResponse[] response = new BaseResponse[]{null};
post(url, paramData, new ResponseCallback() {
@Override
public void onResponse(int resultCode, String resultJson) {
if (200 == resultCode) {
BaseResponse r = JSONUtil.toBean(resultJson, BaseResponse.class);
r.setErrmsg(resultJson);
response[0] = r;
} else {//請求本身就失敗了
response[0] = new BaseResponse();
response[0].setErrcode(String.valueOf(resultCode));
response[0].setErrmsg("請求失敗");
}
}
});
return response[0];
}
/**
* 發起HTTP POST同步請求 jdk8使用函數式方式處理請求結果 jdk6使用內部類方式處理請求結果
*
* @param url 請求對應的URL地址
* @param paramData 請求所帶參數,目前支持JSON格式的參數
* @param fileList 需要一起發送的文件列表
* @param callback
* 請求收到響應後回調函數,參數有2個,第一個爲resultCode,即響應碼,比如200爲成功,404爲不存在,500爲服務器發生錯誤;
* 第二個爲resultJson,即響應回來的數據報文
*/
public static void post(String url, String paramData, List<File> fileList,
ResponseCallback callback) {
doRequest(MyNetWorkCenter.RequestMethod.POST, url, paramData, fileList, callback);
}
public static BaseResponse post(String url, String paramData, List<File> fileList) {
final BaseResponse[] response = new BaseResponse[]{null};
post(url, paramData, fileList, new ResponseCallback() {
@Override
public void onResponse(int resultCode, String resultJson) {
if (200 == resultCode) {
BaseResponse r = JSONUtil.toBean(resultJson, BaseResponse.class);
if (StrUtil.isBlank(r.getErrcode())) {
r.setErrcode("0");
}
r.setErrmsg(resultJson);
response[0] = r;
} else {//請求本身就失敗了
response[0] = new BaseResponse();
response[0].setErrcode(String.valueOf(resultCode));
response[0].setErrmsg("請求失敗");
}
}
});
return response[0];
}
/**
* 發起HTTP GET同步請求 jdk8使用函數式方式處理請求結果 jdk6使用內部類方式處理請求結果
*
* @param url 請求對應的URL地址
* @param paramMap GET請求所帶參數Map,即URL地址問號後面所帶的鍵值對,很蛋疼的實現方式,後續得改進,還沒什麼好的方案
* @param callback
* 請求收到響應後回調函數,參數有2個,第一個爲resultCode,即響應碼,比如200爲成功,404爲不存在,500爲服務器發生錯誤;
* 第二個爲resultJson,即響應回來的數據報文
*/
public static void get(String url, Map<String, String> paramMap, ResponseCallback callback) {
String paramData = null;
if (null != paramMap && !paramMap.isEmpty()) {
StringBuilder buffer = new StringBuilder();
//根據傳進來的參數拼url後綴- -!
for (Map.Entry<String, String> param : paramMap.entrySet()) {
buffer.append(param.getKey()).append("=").append(param.getValue()).append("&");
}
//去掉最後一個&符號
paramData = buffer.substring(0, buffer.length() - 1);
}
doRequest(MyNetWorkCenter.RequestMethod.GET, url, paramData, null, callback);
}
public static BaseResponse get(String url) {
final BaseResponse[] response = new BaseResponse[]{null};
doRequest(MyNetWorkCenter.RequestMethod.GET, url, null, null, new ResponseCallback() {
@Override
public void onResponse(int resultCode, String resultJson) {
if (200 == resultCode) {
BaseResponse r = JSONUtil.toBean(resultJson, BaseResponse.class);
if (StrUtil.isBlank(r.getErrcode())) {
r.setErrcode("0");
}
r.setErrmsg(resultJson);
response[0] = r;
} else {//請求本身就失敗了
response[0] = new BaseResponse();
response[0].setErrcode(String.valueOf(resultCode));
response[0].setErrmsg("請求失敗");
}
}
});
return response[0];
}
/**
* 處理HTTP請求 基於org.apache.http.client包做了簡單的二次封裝
*
* @param method HTTP請求類型
* @param url 請求對應的URL地址
* @param paramData 請求所帶參數,目前支持JSON格式的參數
* @param fileList 需要一起發送的文件列表
* @param callback
* 請求收到響應後回調函數,參數有2個,第一個爲resultCode,即響應碼,比如200爲成功,404爲不存在,500爲服務器發生錯誤;
* 第二個爲resultJson,即響應回來的數據報文
*/
private static void doRequest(final RequestMethod method, final String url,
final String paramData, final List<File> fileList, final ResponseCallback callback) {
//如果url沒有傳入,則直接返回
if (null == url || url.isEmpty()) {
LOG.warn("The url is null or empty!!You must give it to me!OK?");
return;
}
String ishttp = url.toLowerCase();
if (ishttp.startsWith("https") || ishttp.startsWith("HTTPS")) {
doRequestSSH(method, url, paramData, fileList, callback);
return;
}
//默認期望調用者傳入callback函數
boolean haveCallback = true;
/*
* 支持不傳回調函數,只輸出一個警告,並改變haveCallback標識
* 用於一些不需要後續處理的請求,比如只是發送一個心跳包等等
*/
if (null == callback) {
LOG.warn("--------------no callback block!--------------");
haveCallback = false;
}
LOG.debug("-----------------請求地址:{}-----------------", url);
//配置請求參數
RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(CONNECT_TIMEOUT).setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(CONNECT_TIMEOUT).build();
CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
HttpUriRequest request = null;
switch (method) {
case GET:
String getUrl = url;
if (null != paramData) {
getUrl += "?" + paramData;
}
request = new HttpGet(getUrl);
break;
case POST:
LOG.debug("請求入參:");
LOG.debug(paramData);
request = new HttpPost(url);
//上傳文件
if (null != fileList && !fileList.isEmpty()) {
LOG.debug("上傳文件...");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
for (File file : fileList) {
//只能上傳文件哦 ^_^
if (file.isFile()) {
FileBody fb = new FileBody(file);
builder.addPart("media", fb);
} else {//如果上傳內容有不是文件的,則不發起本次請求
LOG.warn("The target '{}' not a file,please check and try again!", file.getPath());
return;
}
}
if (null != paramData) {
builder.addPart("description", new StringBody(paramData, ContentType.APPLICATION_JSON));
}
((HttpPost) request).setEntity(builder.build());
} else//不上傳文件的普通請求
{
if (null != paramData) {
// 目前支持JSON格式的數據
StringEntity jsonEntity = new StringEntity(paramData, ContentType.APPLICATION_JSON);
((HttpPost) request).setEntity(jsonEntity);
}
}
break;
case PUT:
case DELETE:
default:
LOG.warn("-----------------請求類型:{} 暫不支持-----------------", method.toString());
break;
}
CloseableHttpResponse response = null;
try {
long start = System.currentTimeMillis();
//發起請求
response = client.execute(request);
long time = System.currentTimeMillis() - start;
LOG.debug("本次請求'{}'耗時:{}ms", url.substring(url.lastIndexOf("/") + 1, url.length()), time);
int resultCode = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
//此流不是操作系統資源,不用關閉,ByteArrayOutputStream源碼裏close也是個空方法-0_0-
// OutputStream os = new ByteArrayOutputStream();
// entity.writeTo(os);
// String resultJson = os.toString();
String resultJson = EntityUtils.toString(entity, UTF_8);
//返回碼200,請求成功;其他情況都爲請求出現錯誤
if (HttpStatus.SC_OK == resultCode) {
LOG.debug("-----------------請求成功-----------------");
LOG.debug("響應結果:");
LOG.debug(resultJson);
if (haveCallback) {
callback.onResponse(resultCode, resultJson);
}
} else if (haveCallback) {
LOG.warn("-----------------請求出現錯誤,錯誤碼:{}-----------------", resultCode);
callback.onResponse(resultCode, resultJson);
}
} catch (ClientProtocolException e) {
LOG.error("ClientProtocolException:", e);
LOG.warn("-----------------請求出現異常:{}-----------------", e.toString());
if (haveCallback) {
callback.onResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.toString());
}
} catch (IOException e) {
LOG.error("IOException:", e);
LOG.warn("-----------------請求出現IO異常:{}-----------------", e.toString());
if (haveCallback) {
callback.onResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.toString());
}
} catch (Exception e) {
LOG.error("Exception:", e);
LOG.warn("-----------------請求出現其他異常:{}-----------------", e.toString());
if (haveCallback) {
callback.onResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.toString());
}
} finally {
//abort the request
if (null != request && !request.isAborted()) {
request.abort();
}
//close the connection
HttpClientUtils.closeQuietly(client);
HttpClientUtils.closeQuietly(response);
}
}
}
package com.fastwixinextend;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class SslUtils {
/**
* 繞過驗證
*
* @return
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
*/
public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sc = SSLContext.getInstance("SSLv3");
// 實現一個X509TrustManager接口,用於繞過驗證,不用修改裏面的方法
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sc.init(null, new TrustManager[]{trustManager}, null);
return sc;
}
private static void trustAllHttpsCertificates() throws Exception {
TrustManager[] trustAllCerts = new TrustManager[1];
TrustManager tm = new miTM();
trustAllCerts[0] = tm;
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
static class miTM implements TrustManager, X509TrustManager {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public boolean isServerTrusted(X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(X509Certificate[] certs) {
return true;
}
public void checkServerTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
public void checkClientTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
}
/**
* 忽略HTTPS請求的SSL證書,必須在openConnection之前調用
*
* @throws Exception
*/
public static void ignoreSsl() throws Exception {
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String urlHostName, SSLSession session) {
System.out.println("Warning: URL Host: " + urlHostName + " vs. " + session.getPeerHost());
return true;
}
};
trustAllHttpsCertificates();
HttpsURLConnection.setDefaultHostnameVerifier(hv);
}
}