zoukankan      html  css  js  c++  java
  • https请求绕过TLSv1协议的工具类【调整】

    https请求地址绕过证书,报TLSv1请求协议问题,下方工具类能有效的解决:

    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.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    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.SSLContext;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.commons.lang.StringUtils;
    
    
    
    /**
     * http post发送工具
     * 
     * @author King
     *
     */
    public class WCHttpsTool {
    	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());
    	}
    	
    	private static class TrustAnyTrustManager implements X509TrustManager {
    		@Override
    		public void checkClientTrusted(X509Certificate[] chain, String authType)
    				throws CertificateException {
    		}
    
    		@Override
    		public void checkServerTrusted(X509Certificate[] chain, String authType)
    				throws CertificateException {
    		}
    
    		@Override
    		public X509Certificate[] getAcceptedIssuers() {
    			return null;
    		}
    	}
    
    	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 King
    	 */
    	@SuppressWarnings("null")
    	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("
    ");
    		reqDetailProcedure.append("请求地址:【" + urlStr + "】").append("
    ");
    		reqDetailProcedure.append("真实请求方式及编码:【post " + sendEncoding + "】").append("
    ");
    		reqDetailProcedure.append("期望返回编码:【" + recvEncoding + "】").append("
    ");
    		reqDetailProcedure.append("请求超时时间:【" + readTimeout / 1000 + "s】").append("
    ");
    		reqDetailProcedure.append("请求报文:【" + requestData + "】").append("
    ");
    		try {
    //			如有必要,给?后的参数加encode(xxx,"UTF-8"),不然目标系统可能收到的request.getParameter()是乱码
    //			String arg = java.net.URLEncoder.encode("中国","UTF-8");
    //			url = new URL(urlStr+"?deptname="+arg);
    			System.setProperty("https.protocols", "TLSv1");  
    	        SSLContext sc = SSLContext.getInstance("TLSv1"); 
                sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
    			
    			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/1943310  或 http://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("
    ");
    			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("
    ");// 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("
    ");
    			reqDetailProcedure.append("返回HEAD头信息:【" + conn.getHeaderFields() + "】").append("
    ");
    			reqDetailProcedure.append("返回报文:【" + retBuilder.toString() + "】").append("
    ");
    			Date endTime = new Date();
    			reqDetailProcedure.append("返回时间:【" + DATE_FORMATER.format(endTime) + "】").append("
    ");
    			long diffMilliSecond = endTime.getTime() - startTime.getTime();
    			long diffSecond = (diffMilliSecond / 1000);
    			reqDetailProcedure.append("耗时:【" + diffMilliSecond + "】毫秒,大约" + "【" + diffSecond + "】秒").append("
    ");
    			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 King
    	 */
    	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 King 金剑波
    	 * @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 King
    	 */
    	/*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);// 大家最终只要使用这一句代码就可调用
    	}
    }
    
  • 相关阅读:
    tomcat 添加用户名和密码
    linux系统下获取cpu、硬盘、内存使用率
    snmp 企业对应的mib编号
    String加密解密 2017.07.26
    Mongo日期
    linux sed 批量替换多个文件中的字符串
    Python和giL的关系
    vim
    乌班图
    Python
  • 原文地址:https://www.cnblogs.com/hmhhz/p/11996067.html
Copyright © 2011-2022 走看看