【fastweixin框架教程3】JAVA進行HTTPS網站訪問,PKIX path building failed解決方法

  上幾篇文章我們談到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);
    }
}

發佈了1023 篇原創文章 · 獲贊 273 · 訪問量 1030萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章