https請求之繞過證書安全校驗工具類(原)


package com.isoftstone.core.util;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;


/**
 * https post發送工具
 * 
 * @author 超神之巔
 *
 */
public class HttpsTool {
    private static final String LINE_SEPARATOR = System.getProperty("line.separator");
    
    static HostnameVerifier hv = new HostnameVerifier() {
        public boolean verify(String urlHostName, SSLSession session) {
            System.out.println("Warning: URL Host: " + urlHostName + " vs. "
                    + session.getPeerHost());
            return true;
        }
    };
    
    private static void trustAllHttpsCertificates() throws Exception {
        javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
        javax.net.ssl.TrustManager tm = new miTM();
        trustAllCerts[0] = tm;
        javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext
                .getInstance("SSL");
        sc.init(null, trustAllCerts, null);
        javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc
                .getSocketFactory());
    }

    static class miTM implements javax.net.ssl.TrustManager,
            javax.net.ssl.X509TrustManager {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public boolean isServerTrusted(
                java.security.cert.X509Certificate[] certs) {
            return true;
        }

        public boolean isClientTrusted(
                java.security.cert.X509Certificate[] certs) {
            return true;
        }

        public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType)
                throws java.security.cert.CertificateException {
            return;
        }

        public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType)
                throws java.security.cert.CertificateException {
            return;
        }
    }
    
    /**
     * 發送報文
     * 
     * 通信失敗時返回分兩種:一種是拋異常,一種是返回"",本方法取前者
     * 
     * @param requestData
     *            請求報文
     * @param headMap
     *            head請求頭參數 conn.setRequestProperty(key,value)
     * @param urlStr
     *            請求地址
     * @param sendEncoding
     *            請求編碼
     * @param recvEncoding
     *            返回編碼
     * @param connectionTimeout
     *            鏈接超時時間 1000代表 1秒
     * @param readTimeout
     *            讀取超時時間 1000代表1秒
     * @return
     * @throws IOException
     * @author 超神之巔
     */
    public static String send(String requestData,Map<String,String> headMap, String urlStr, String sendEncoding, String recvEncoding, int connectionTimeout, int readTimeout,String contentType) throws Exception {
        URL url = null;
        HttpsURLConnection conn = null;
        ByteArrayOutputStream byteOut = null;
        BufferedReader readInfo = null;
        StringBuilder retBuilder = new StringBuilder();// 這里用不着多線程安全的StringBuffer
        OutputStream out = null;
        String line = null;
        StringBuilder reqDetailProcedure = new StringBuilder();// 這里用不着多線程安全的StringBuffer
        Date startTime = new Date();
        reqDetailProcedure.append("請求時間:【" + DATE_FORMATER.format(startTime) + "】").append("\r\n");
        reqDetailProcedure.append("請求地址:【" + urlStr + "】").append("\r\n");
        reqDetailProcedure.append("真實請求方式及編碼:【post " + sendEncoding + "】").append("\r\n");
        reqDetailProcedure.append("期望返回編碼:【" + recvEncoding + "】").append("\r\n");
        reqDetailProcedure.append("請求超時時間:【" + readTimeout / 1000 + "s】").append("\r\n");
        reqDetailProcedure.append("請求報文:【" + requestData + "】").append("\r\n");
        try {
//            如有必要,給?后的參數加encode(xxx,"UTF-8"),不然目標系統可能收到的request.getParameter()是亂碼
//            String arg = java.net.URLEncoder.encode("中國","UTF-8");
//            url = new URL(urlStr+"?deptname="+arg);
            
            url = new URL(urlStr);
            
            trustAllHttpsCertificates();
            HttpsURLConnection.setDefaultHostnameVerifier(hv);
            
            conn = (HttpsURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            // 新增部分
            //conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
            conn.setRequestProperty("SOAPAction", "\"\"");
            conn.setRequestProperty("Accept", "application/xml, application/json,application/dime, multipart/related, text/*");

            // 如果沒有下面這一行代碼,服務器端可以通過request.getParameter()和request.getInputStream()都接收到相同信息

            // Content-Type相關知識鏈接: http://www.cnblogs.com/whatlonelytear/p/6187575.html
            // conn如果不設Content-Type,則默認成application/x-www-form-urlencoded
            // 當然也可以配置成application/x-www-form-urlencoded;charset=UTF-8,此時要求服務端返回UTF-8編碼,如果本地還用gbk去解碼,有可能得到亂碼
            conn.setRequestProperty("Content-Type", contentType);
            // 如果把Content-Type的類型改變成非application/x-www-form-urlencoded,如改成text/xml,
            // 則目標服務器端僅能通過request.getInputStream()接收信息, 如conn.setRequestProperty("Content-Type", "text/xml;charset=GBK");
            // Content-Type各類型解釋: http://blog.csdn.net/blueheart20/article/details/45174399
            
            // conn.setRequestProperty("Accept-Charset", "utf-8");//未知
            
            //Cache-Control說明鏈接:http://huangyunbin.iteye.com/blog/1943310http://www.cnblogs.com/whatlonelytear/articles/6385390.html
            conn.setRequestProperty("Cache-Control", "no-cache");
            
            //設置head頭,如果已存在,則覆蓋之前的head配置
            if(headMap != null){
                for(Map.Entry<String, String > entry : headMap.entrySet()){
                    conn.setRequestProperty(entry.getKey(),entry.getValue());
                }
                
            }
            
            // conn.setRequestProperty("appName", appName);//各系統需要設置應用系統名,如電銷為telesales(無意義,本人自定義)
            conn.setUseCaches(false); // 忽略緩存
            // get請求用不到conn.getOutputStream(),因為參數直接追加在地址后面,因此默認是false.
            // post請求(比如:文件上傳)需要往服務區傳輸大量的數據,這些數據是放在http的body里面的,因此需要在建立連接以后,往服務端寫數據.
            // 因為總是使用conn.getInputStream()獲取服務端的響應,因此默認值是true.
            conn.setDoOutput(true); // 使用 URL
                                    // 連接進行輸出,允許使用conn.getOutputStream().write()
            conn.setDoInput(true); // 使用 URL
                                    // 連接進行輸入,允許使用conn.getInputStream().read();
            conn.setConnectTimeout(connectionTimeout);// 鏈接超時
            conn.setReadTimeout(readTimeout);// 讀取超時
            conn.connect();// 建立鏈接
            byteOut = new ByteArrayOutputStream();
            byteOut.write(requestData.getBytes(sendEncoding));// 以指定編碼發送,如果有亂碼,修改之
            byte[] buf = byteOut.toByteArray();
            out = conn.getOutputStream();
            out.write(buf);
            out.flush();
            reqDetailProcedure.append("響應碼和狀態:【" + conn.getResponseCode() + "/" + conn.getResponseMessage() + "】").append("\r\n");
            if (HttpURLConnection.HTTP_OK == conn.getResponseCode()) {// 正確返回
                InputStream tempStream = conn.getInputStream();
                readInfo = new BufferedReader(new java.io.InputStreamReader(tempStream, recvEncoding));// 以指定編碼讀取返回信息,如果有亂碼,修改之
                while ((line = readInfo.readLine()) != null) {
                    retBuilder.append(line).append(LINE_SEPARATOR);
                }
            } else {// 沒有正確返回
                // 這個else分支有冗余代碼,一來代碼不多,二來這個分支是經過長時間思考,還是保留了下來,方便我以后對錯誤做不拋異常處理等
                InputStream tempStream = conn.getInputStream();// 如果響應碼不是200,一般在這里就開始報異常,不會走到下面幾行中去的.
                readInfo = new BufferedReader(new java.io.InputStreamReader(tempStream, recvEncoding));// cannotReach
                while ((line = readInfo.readLine()) != null) {// cannotReach
                    retBuilder.append(line);// cannotReach
                }// cannotReach
                reqDetailProcedure.append("@@返回異常報文:【" + retBuilder + "】").append("\r\n");// cannotReach
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            // 目標服務端用response.setContentType("text/html;charset=UTF-8");然后源調用方可以用conn.getContentType()獲取到[猜測,暫未測試]
            // conn.getContentType()包含在Head返回的內容中.
            // 返回如果帶編碼,可以做成動態編碼去把流轉成字符串,暫不優化.這是極好的l優化點.
            reqDetailProcedure.append("返回內容類型及編碼:【" + conn.getContentType() + "】").append("\r\n");
            reqDetailProcedure.append("返回HEAD頭信息:【" + conn.getHeaderFields() + "】").append("\r\n");
            reqDetailProcedure.append("返回報文:【" + retBuilder.toString() + "】").append("\r\n");
            Date endTime = new Date();
            reqDetailProcedure.append("返回時間:【" + DATE_FORMATER.format(endTime) + "】").append("\r\n");
            long diffMilliSecond = endTime.getTime() - startTime.getTime();
            long diffSecond = (diffMilliSecond / 1000);
            reqDetailProcedure.append("耗時:【" + diffMilliSecond + "】毫秒,大約" + "【" + diffSecond + "】秒").append("\r\n");
            System.out.println(reqDetailProcedure.toString());
            //ThreadLocalListContainer.put(reqDetailProcedure.toString());
            // ThreadLocalMapContainer.put(KingConstants.REQ_DETAIL_PROCEDURE,reqDetailProcedure.toString())
            try {
                if (readInfo != null) {
                    readInfo.close();
                }
                if (byteOut != null) {
                    byteOut.close();
                }
                if (out != null) {
                    out.close();
                }
                if (conn != null) {
                    conn.disconnect();
                }
            } catch (Exception e) {
                System.out.println("關閉鏈接出錯!" + e.getMessage());
            }

        }
        return retBuilder.toString();
    }
    
    /**
     * 發送報文
     * 
     * 通信失敗時返回分兩種:一種是拋異常,一種是返回"",本方法取前者
     * 
     * @param requestData
     *            請求報文
     * @param urlStr
     *            請求地址
     * @param sendEncoding
     *            請求編碼
     * @param recvEncoding
     *            返回編碼
     * @param connectionTimeout
     *            鏈接超時時間 1000代表 1秒
     * @param readTimeout
     *            讀取超時時間 1000代表1秒
     * @return
     * @throws IOException
     * @author 超神之巔
     */
    public static String send(String requestData, String urlStr, String sendEncoding, String recvEncoding, int connectionTimeout, int readTimeout) throws Exception {
        boolean flag = isJson(requestData);//是否JSON
        String contentType="application/soap+xml";
        if(flag) {
            contentType = "application/json";
        }
        return send( requestData,null, urlStr, sendEncoding, recvEncoding, connectionTimeout, readTimeout,contentType);
    }

    /**
     * 
     * @param filePath
     *            文件絕對路徑
     * @param encoding
     *            讀取文件的編碼
     * @return
     * @author 超神之巔
     * @throws Exception
     */
    public static String readStringFromFile(String filePath, String encoding) {
        File file = new File(filePath);
        // System.out.println("文件 "+filePath+"存在與否?: "+ file.exists());
        String tempLine = null;
        String retStr = "";
        InputStreamReader isr = null;// way1:
        // FileReader fr = null;//way2
        StringBuilder sb = new StringBuilder();
        try {
            if (file.exists()) {
                isr = new InputStreamReader(new FileInputStream(file), encoding);// way1:
                // fr = new FileReader(file);//way2
                BufferedReader br = new BufferedReader(isr);// way1:
                // BufferedReader br = new BufferedReader(fr);;//way2:
                tempLine = br.readLine();
                while (tempLine != null) {
                    sb.append(tempLine).append(System.getProperty("line.separator"));
                    tempLine = br.readLine();
                }
                retStr = sb.toString();
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (isr != null)
                    isr.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // System.out.println("讀到的文件內容如下:");
        // System.out.println(retStr);
        return retStr;
    }
    /**
     * 判斷字符串是否為JSON格式
     * @param str
     * @return
     */
    public static boolean isJson(String str){
        if (StringUtils.isBlank(str)) {
            return false;
        }
        
        boolean flag1 = (str.startsWith("{") && str.endsWith("}"));
        boolean flag2 = (str.startsWith("[") && str.endsWith("]"));
        
        return (flag1 || flag2);
    }

    /*public static final void writeInfo(HttpServletResponse resp, String errorCode, String respInfo, Map<String, Object> map) {
        map.put("errorCode", errorCode);
        map.put("respInfo", respInfo);
        String detail = ThreadLocalListContainer.getAll();
        map.put(KingConstants.DETAIL_PROCEDURE, detail);
        ThreadLocalListContainer.clearAll();
        // map.put(KingConstants.DETAIL_PROCEDURE, detail);
        try {
//            String gsonInfo = new Gson().toJson(map);//old
            Gson gson = new GsonBuilder().setPrettyPrinting().create();//new
            String gsonInfo = gson.toJson(map);
            PrintWriter pw = resp.getWriter();
            pw.print(gsonInfo);
            pw.flush();
            pw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }*/

    /**
     * 
     * @param resp
     * @param errorCode
     * @param respInfo
     * @param map
     * ......
     * @time 2017年4月23日 上午9:12:43
     * @author 超神之巔
     */
    /*public static final void writeInfo(HttpServletResponse resp, KingResp result) {
        String detail = ThreadLocalListContainer.getAll();
        result.setDetailProcedure(detail);
        ThreadLocalListContainer.clearAll();
        try {
//            String gsonInfo = new Gson().toJson(map);//old
            Gson gson = new GsonBuilder().setPrettyPrinting().create();//new
            String gsonInfo = gson.toJson(result);
            FileTool.writeStringToFile("d:/temp/myinfo.txt", gsonInfo, "gbk", false);
            PrintWriter pw = resp.getWriter();
            pw.print(gsonInfo);
            pw.flush();
            pw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }*/
    
    public static final void writeInfo(HttpServletResponse resp, String respInfo) {
        try {
            PrintWriter pw = resp.getWriter();
            pw.print(respInfo);
            pw.flush();
            pw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public static final SimpleDateFormat DATE_FORMATER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:sss");

    public static void main(String[] args) throws Exception {
        String requestUrl  = "https://bx.zhcgs.gov.cn:8060/NewBxInfo/BxInfo.asmx";
        //把cacerts20181015文到該目錄
        System.setProperty("javax.net.ssl.trustStore",
                "K:\\myprogram\\jdk\\jdk8\\jdk1.8.0_141\\jre\\lib\\security\\cacerts20181015");
        String requestData = readStringFromFile("d:/file/send.xml", "UTF-8");// 有亂碼,請修改指定編碼
        String sencXml = HttpsTool.send(requestData, requestUrl, "utf-8", "utf-8", 300 * 1000, 300 * 1000);// 大家最終只要使用這一句代碼就可調用
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM