关于证书
1、每个人都可以使用一些证书生成工具为自己的https站点生成证书(比如JDK的keytool),大家称它为“自签名证书”,但是自己生成的证书是不被浏览器承认的,所以浏览器会报安全提示,要求你手动安装证书,提示风险,是否继续等。只有通过权威的CA机构付费获得的证书才能被浏览器承认。
2、证书(无客户端服务端之分)保存着IP信息、证书过期时间、证书所有者地址信息等。
双向认证
1、先决条件是有两个或两个以上的证书,一个是服务端证书,另一个或多个是客户端证书。
2、服务端保存着客户端的证书并信任该证书,客户端保存着服务端的证书并信任该证书。这样,在证书验证成功的情况下即可完成请求响应。
3、双向认证安全性更高。
单向认证
1、客户端保存着服务端的证书并信任该证书即可。
2、https一般是单向认证,这样可以让绝大部分人可以访问你的站点。
使用示例代码:
public interface PCIHttpClient { /** 请求头信息:Content-Type **/ public static final String CONTENT_TYPE = "Content-Type"; /** 请求头信息:User-Agent **/ public static final String USER_AGENT = "User-Agent"; /** 默认的内容类型 **/ public static final String DEFAULT_CONTENTTYPE = "application/x-www-form-urlencoded;charset=UTF-8"; /** 默认的用户代理(浏览器类型) **/ public static final String DEFAULT_USERAGENT = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; InfoPath.1; .NET CLR 1.1.4322; CIBA)"; /** 默认的读取超时时间(单位毫秒) **/ public static final int DEFAULT_TIMEOUT = 180000; /** 默认的连接超时时间(单位毫秒) **/ public static final int DEFAULT_CONNECTION_TIMEOUT = 60000; /** * 发送GET方式请求数据,并接收响应数据 * * @param url 请求地址 * @param timeout 超时时间(单位毫秒) * @return 响应内容(字符串) * @throws IOException */ public String sendGetAndResponseAsString(String url, int timeout) throws IOException; /** * 发送GET方式请求数据,并接收响应数据 * * @param url 请求地址 * @param headers 请求头信息 * @param timeout 超时时间(单位毫秒) * @return 响应内容(字符串) * @throws IOException */ public String sendGetAndResponseAsString(String url, Map<String, String> headers, int timeout) throws IOException; /** * 发送GET方式请求数据,并接收响应数据 * * @param url 请求地址 * @param headers 请求头信息 * @param params 请求参数 * @param charsetName 字符编码 * @param timeout 超时时间(单位毫秒) * @return 响应内容(字符串) * @throws IOException */ public String sendGetAndResponseAsString(String url, Map<String, String> headers, Map<String, String> params, String charsetName, int timeout) throws IOException; /** * 发送GET方式请求数据,并接收响应数据 * * @param url 请求地址 * @param timeout 超时时间(单位毫秒) * @return 响应内容(字节数组) * @throws IOException */ public byte[] sendGetAndResponseAsByteArray(String url, int timeout) throws IOException; /** * 发送GET方式请求数据,并接收响应数据 * * @param url 请求地址 * @param headers 请求头信息 * @param timeout 超时时间(单位毫秒) * @return 响应内容(字节数组) * @throws IOException */ public byte[] sendGetAndResponseAsByteArray(String url, Map<String, String> headers, int timeout) throws IOException; /** * 发送GET方式请求数据,并接收响应数据 * * @param url 请求地址 * @param headers 请求头信息 * @param params 请求参数 * @param charsetName 字符编码 * @param timeout 超时时间(单位毫秒) * @return 响应内容(字节数组) * @throws IOException */ public byte[] sendGetAndResponseAsByteArray(String url, Map<String, String> headers, Map<String, String> params, String charsetName, int timeout) throws IOException; /** * 发送GET方式请求数据,并接收响应数据 * * @param url 请求地址 * @param headers 请求头信息 * @param params 请求参数 * @param charsetName 字符编码 * @param timeout 超时时间(单位毫秒) * @return 响应内容(输入流) * @throws IOException */ public InputStream sendGetAndResponseAsStream(String url, Map<String, String> headers, Map<String, String> params, String charsetName, int timeout) throws IOException; /** * 发送GET方式请求 * * @param url 请求地址 * @param headers 请求头信息 * @param params 请求参数 * @param charsetName 字符编码 * @param timeout 超时时间(单位毫秒) * @param output 响应内容(输出流) * @throws IOException */ public void sendGet(String url, Map<String, String> headers, Map<String, String> params, String charsetName, int timeout, OutputStream output) throws IOException; /** * 发送POST方式请求数据,并接收响应数据 * * @param url 请求地址 * @param params 请求参数 * @param charsetName 字符编码 * @param timeout 超时时间(单位毫秒) * @return 响应内容(字符串) * @throws IOException */ public String sendPostAndResponseAsString(String url, Map<String, String> params, String charsetName, int timeout) throws IOException; /** * 发送POST方式请求数据,并接收响应数据 * * @param url 请求地址 * @param headers 请求头信息 * @param params 请求参数 * @param timeout 超时时间(单位毫秒) * @param charsetName 字符编码 * @return 响应内容(字符串) * @throws IOException */ public String sendPostAndResponseAsString(String url, Map<String, String> headers, Map<String, String> params, int timeout, String charsetName) throws IOException; /** * 发送POST方式请求数据,并接收响应数据 * * @param url 请求地址 * @param headers 请求头信息 * @param stringOrStream 请求体内容(字符串或者输入流) * @param charsetName 字符编码 * @param timeout 超时时间(单位毫秒) * @return 响应内容(字符串) * @throws IOException */ public String sendPostAndResponseAsString(String url, Map<String, String> headers, Object stringOrStream, String charsetName, int timeout) throws IOException; /** * 发送POST方式请求数据,并接收响应数据 * * @param url 请求地址 * @param headers 请求头信息 * @param params 请求参数 * @param stringOrStream 请求体内容(字符串或者输入流) * @param charsetName 字符编码 * @param timeout 超时时间(单位毫秒) * @return 响应内容(字符串) * @throws IOException */ public String sendPostAndResponseAsString(String url, Map<String, String> headers, Map<String, String> params, Object stringOrStream, String charsetName, int timeout) throws IOException; /** * 发送POST方式请求数据,并接收响应数据 * * @param url 请求地址 * @param params 请求参数 * @param charsetName 字符编码 * @param timeout 超时时间(单位毫秒) * @return 响应内容(字节数组) * @throws IOException */ public byte[] sendPostAndResponseAsByteArray(String url, Map<String, String> params, String charsetName, int timeout) throws IOException; /** * 发送POST方式请求数据,并接收响应数据 * * @param url 请求地址 * @param headers 请求头信息 * @param params 请求参数 * @param timeout 超时时间(单位毫秒) * @param charsetName 字符编码 * @return 响应内容(字节数组) * @throws IOException */ public byte[] sendPostAndResponseAsByteArray(String url, Map<String, String> headers, Map<String, String> params, int timeout, String charsetName) throws IOException; /** * 发送POST方式请求数据,并接收响应数据 * * @param url 请求地址 * @param headers 请求头信息 * @param stringOrStream 请求体内容(字符串或者输入流) * @param charsetName 字符编码 * @param timeout 超时时间(单位毫秒) * @return 响应内容(字节数组) * @throws IOException */ public byte[] sendPostAndResponseAsByteArray(String url, Map<String, String> headers, Object stringOrStream, String charsetName, int timeout) throws IOException; /** * 发送POST方式请求数据,并接收响应数据 * * @param url 请求地址 * @param headers 请求头信息 * @param params 请求参数 * @param stringOrStream 请求体内容(字符串或者输入流) * @param charsetName 字符编码 * @param timeout 超时时间(单位毫秒) * @return 响应内容(字节数组) * @throws IOException */ public byte[] sendPostAndResponseAsByteArray(String url, Map<String, String> headers, Map<String, String> params, Object stringOrStream, String charsetName, int timeout) throws IOException; /** * 发送POST方式请求数据,并接收响应数据 * * @param url 请求地址 * @param headers 请求头信息 * @param params 请求参数 * @param stringOrStream 请求体内容(字符串或者输入流) * @param charsetName 字符编码 * @param timeout 超时时间(单位毫秒) * @return 响应内容(输入流) * @throws IOException */ public InputStream sendPostAndResponseAsStream(String url, Map<String, String> headers, Map<String, String> params, Object stringOrStream, String charsetName, int timeout) throws IOException; /** * 发送POST方式请求 * * @param url 请求地址 * @param headers 请求头信息 * @param params 请求参数 * @param stringOrStream 请求体内容(字符串或者输入流) * @param charsetName 字符编码 * @param timeout 超时时间(单位毫秒) * @param output 响应内容(输出流) * @throws IOException */ public void sendPost(String url, Map<String, String> headers, Map<String, String> params, Object stringOrStream, String charsetName, int timeout, OutputStream output) throws IOException; /** * 发送GET方式请求 * * @param url 请求地址 * @param headers 请求头信息 * @param params 请求参数 * @param charsetName 字符编码 * @param timeout 超时时间(单位毫秒) * @return * @throws IOException * * @since 2.0.0 */ public PCIHttpResponse sendGet(String url, Map<String, String> headers, Map<String, String> params, String charsetName, int timeout) throws IOException; /** * 发送POST方式请求 * * @param url 请求地址 * @param headers 请求头信息 * @param params 请求参数 * @param stringOrStream 请求体内容(字符串或者输入流) * @param charsetName 字符编码 * @param timeout 超时时间(单位毫秒) * @return * @throws IOException * * @since 2.0.0 */ public PCIHttpResponse sendPost(String url, Map<String, String> headers, Map<String, String> params, Object stringOrStream, String charsetName, int timeout) throws IOException; }
public class CustomConstants { /** 字符编码:UTF-8 */ public static final String CHARSET_UTF8 = "UTF-8"; }
public class CustomStringUtils { private static LogUtils logger = new LogUtils(CustomStringUtils.class); /** * 长度不足,左补字符 * @param str * @param ch * @param len * @return */ public static String leftFill(String str, char ch, int len) { if (str == null) { str = ""; } while (str.length() < len) { str = ch + str; } return str; } /** * 长度不足,右补字符 * @param str * @param ch * @param len * @return */ public static String rightFill(String str, char ch, int len) { if (str == null) { str = ""; } while (str.length() < len) { str = str + ch; } return str; } /** * 拼接字符串 * @param objs * @return */ public static String append(Object... objs) { if (objs == null || objs.length == 0) { return ""; } StringBuffer buffer = new StringBuffer(); for (Object obj : objs) { buffer.append(obj); } return buffer.toString(); } /** * 如果字符串为空,则返回空字符 * @param str * @return */ public static String nullToBlank(String str) { return str == null ? "" : str; } /** * 将map转化成字符串 * @param map * @return 格式:key1=value1&key2=value2... */ public static String convertMapToString(Map<String, String> map) { if (map == null || map.isEmpty()) { return null; } StringBuffer buffer = new StringBuffer(); boolean first = true; for (Map.Entry<String, String> entry : map.entrySet()) { if (first) { buffer.append(entry.getKey()).append("=").append(entry.getValue()); first = false; } else { buffer.append("&").append(entry.getKey()).append("=").append(entry.getValue()); } } return buffer.toString(); } /** * 将map转化成字符串,并对map.value进行URL编码 * @param map * @param encoding * @return 格式:key1=value1&key2=value2... */ public static String convertMapToString(Map<String, String> map, String encoding) { if (map == null || map.isEmpty()) { return null; } StringBuffer buffer = new StringBuffer(); boolean first = true; for (Map.Entry<String, String> entry : map.entrySet()) { if (first) { buffer.append(entry.getKey()).append("=").append(urlEncode(entry.getValue(), encoding)); first = false; } else { buffer.append("&").append(entry.getKey()).append("=").append(urlEncode(entry.getValue(), encoding)); } } return buffer.toString(); } /** * 将map转化成字符串(当参数值为null时,则忽略该参数) * @param map * @return 格式:key1=value1&key2=value2... */ public static String convertMapToStringIgnoreNull(Map<String, String> map) { if (map == null || map.isEmpty()) { return null; } StringBuffer buffer = new StringBuffer(); boolean first = true; for (Map.Entry<String, String> entry : map.entrySet()) { if (entry.getValue() == null) { continue; } if (first) { buffer.append(entry.getKey()).append("=").append(entry.getValue()); first = false; } else { buffer.append("&").append(entry.getKey()).append("=").append(entry.getValue()); } } return buffer.toString(); } /** * 将map转化成字符串,并对map.value进行URL编码(当参数值为null时,则忽略该参数) * @param map * @param encoding * @return 格式:key1=value1&key2=value2... */ public static String convertMapToStringIgnoreNull(Map<String, String> map, String encoding) { if (map == null || map.isEmpty()) { return null; } StringBuffer buffer = new StringBuffer(); boolean first = true; for (Map.Entry<String, String> entry : map.entrySet()) { if (entry.getValue() == null) { continue; } if (first) { buffer.append(entry.getKey()).append("=").append(urlEncode(entry.getValue(), encoding)); first = false; } else { buffer.append("&").append(entry.getKey()).append("=").append(urlEncode(entry.getValue(), encoding)); } } return buffer.toString(); } /** * 对字符串进行URL编码 * @param str * @param encoding * @return */ public static String urlEncode(String str, String encoding) { if (str == null || "".equals(str)) { return str; } try { return URLEncoder.encode(str, encoding); } catch (UnsupportedEncodingException e) { logger.error(append("URL encode string error. str=", str, ", encoding=", encoding), e); return str; } } /** * 对字符串进行URL解码 * @param str * @param encoding * @return */ public static String urlDecode(String str, String encoding) { if (str == null || "".equals(str)) { return str; } try { return URLDecoder.decode(str, encoding); } catch (UnsupportedEncodingException e) { logger.error(append("URL decode string error. str=", str, ", encoding=", encoding), e); return str; } } /** * 字符串的字节长度是否超出边界值 * @param str 字符串 * @param bounds 边界值 * @param charsetName 字符编码 * @return */ public static boolean bytesLengthOutOfBounds( String str, int bounds, String charsetName) { if (bounds < 0 || str == null || "".equals(str)) { return false; } try { int bytesLen = str.getBytes(charsetName).length; return bytesLen > bounds; } catch (UnsupportedEncodingException e) { logger.error(append("Check bytes length out of bounds error. str=", str, ", charsetName=", charsetName), e); } return false; } /** * @Title: generate * @Description: 随机生成指定长度的16进制的字符串 * @since: 0.0.1 * @param len 字符串长度 * @return */ public static String generateRandomHex(int len){ if (len < 1) { return null; } StringBuffer sb = new StringBuffer(); Random random = new Random(); for (int i = 0; i < len; i++) { sb.append(Integer.toHexString(random.nextInt(16))); } return sb.toString().toUpperCase(); } /** * @Title: generateConformOddCheckHex * @Description: 生成符合奇校验的字符串 * @since: 0.0.1 * @param len 字节长度 * @return */ public static String generateConformOddCheckHex(int len) { byte[] bytes = new byte[len]; for (int i = 0; i < len; i++) { Random random = new Random(); int randomInt = random.nextInt(255); String binaryString = Integer.toBinaryString(randomInt); boolean oddCheck = isConformOddCheck(binaryString); if (!oddCheck) { randomInt ^= 1; } // System.err.println(Integer.toBinaryString(randomInt)); byte b = (byte) randomInt; bytes[i] = b; } String hexString = CommonUtils.byte2hexString(bytes); return hexString; } /** * @Title: oddCheck * @Description: 检验是否符合奇校验 * @since: 0.0.1 * @param binaryString * @return */ private static boolean isConformOddCheck(String binaryString) { int sum = 0; char[] charArray = binaryString.toCharArray(); for(char c : charArray){ if (c == \'1\') { sum ++; } } if (sum%2 == 1) { return true; } return false; } }
public class IOUtils { private static LogUtils logger = new LogUtils(IOUtils.class); /** 默认的缓冲区大小 **/ private static final int DEFAULT_BUFFER_SIZE = 4096; /** * 将字节输入流转换成字节数组 * @param input * @return * @throws IOException */ public static byte[] toByteArray(InputStream input) throws IOException { ByteArrayOutputStream output = null; try { output = new ByteArrayOutputStream(); copy(input, output); return output.toByteArray(); } finally { closeQuietly(output); } } /** * 将字符输入流转换成字节数组 * @param reader * @return * @throws IOException */ public static byte[] toByteArray(Reader reader) throws IOException { ByteArrayOutputStream output = null; try { output = new ByteArrayOutputStream(); copy(reader, output); return output.toByteArray(); } finally { closeQuietly(output); } } /** * 将字符输入流转换成字节数组 * @param reader * @param encoding * @return * @throws IOException */ public static byte[] toByteArray(Reader reader, String encoding) throws IOException { ByteArrayOutputStream output = null; try { output = new ByteArrayOutputStream(); copy(reader, output, encoding); return output.toByteArray(); } finally { closeQuietly(output); } } /** * 将字节输入流转换成字符串 * @param input * @return * @throws IOException */ public static String toString(InputStream input) throws IOException { StringWriter writer = null; try { writer = new StringWriter(); copy(input, writer); return writer.toString(); } finally { closeQuietly(writer); } } /** * 将字节输入流转换成字符串 * @param input * @param encoding * @return * @throws IOException */ public static String toString(InputStream input, String encoding) throws IOException { StringWriter writer = null; try { writer = new StringWriter(); copy(input, writer, encoding); return writer.toString(); } finally { closeQuietly(writer); } } /** * 将字符输入流转换成字符串 * @param reader * @return * @throws IOException */ public static String toString(Reader reader) throws IOException { StringWriter writer = null; try { writer = new StringWriter(); copy(reader, writer); return writer.toString(); } finally { closeQuietly(writer); } } /** * 按行读取字节输入流 * @param input * @return * @throws IOException */ public static List<String> readLines(InputStream input) throws IOException { // InputStreamReader reader = new InputStreamReader(input); // return readLines(reader); InputStreamReader reader = null; try { reader = new InputStreamReader(input); return readLines(reader); } finally { closeQuietly(reader); } } /** * 按行读取字节输入流 * @param input * @param encoding * @return * @throws IOException */ public static List<String> readLines(InputStream input, String encoding) throws IOException { // if (encoding == null) { // return readLines(input); // } // InputStreamReader reader = new InputStreamReader(input, encoding); // return readLines(reader); if (encoding == null) { return readLines(input); } InputStreamReader reader = null; try { reader = new InputStreamReader(input, encoding); return readLines(reader); } finally { closeQuietly(reader); } } /** * 按行读取字符输入流 * @param reader * @return * @throws IOException */ public static List<String> readLines(Reader reader) throws IOException { // BufferedReader br = new BufferedReader(reader); // List<String> lines = new ArrayList<String>(); // String line = br.readLine(); // while (line != null) { // lines.add(line); // line = br.readLine(); // } // return lines; BufferedReader br = null; try { br = new BufferedReader(reader); List<String> lines = new ArrayList<String>(); String line = br.readLine(); while (line != null) { lines.add(line); line = br.readLine(); } return lines; } finally { closeQuietly(br); } } /** * 阻塞地读取字节输入流 * @param input * @param buffer * @param off * @param length * @throws IOException */ public static void read(InputStream input, byte[] buffer, int off, int length) throws IOException { while (off < length) { off = off + input.read(buffer, off, length - off); if (off < 0) { throw new IOException("读取时出错[readLen=" + off + "]"); } } } /** * 将字节输入流拷贝到字符输出流 * @param input * @param writer * @throws IOException */ public static void copy(InputStream input, Writer writer) throws IOException { // InputStreamReader reader = new InputStreamReader(input); // copy(reader, writer); InputStreamReader reader = null; try { reader = new InputStreamReader(input); copy(reader, writer); } finally { closeQuietly(reader); } } /** * 将字节输入流拷贝到字符输出流 * @param input * @param writer * @param encoding * @throws IOException */ public static void copy(InputStream input, Writer writer, String encoding) throws IOException { // if (encoding == null) { // copy(input, writer); // } else { // InputStreamReader reader = new InputStreamReader(input, encoding); // copy(reader, writer); // } if (encoding == null) { copy(input, writer); } else { InputStreamReader reader = null; try { reader = new InputStreamReader(input, encoding); copy(reader, writer); } finally { closeQuietly(reader); } } } /** * 将字节输入流拷贝到字节输出流 * @param input * @param output * @return 字节数 * @throws IOException */ public static int copy(InputStream input, OutputStream output) throws IOException { byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; int count = 0; int n = 0; while (-1 != (n = input.read(buffer))) { output.write(buffer, 0, n); count += n; } output.flush(); return count; } /** * 将字符输入流拷贝到字节输出流 * @param reader * @param output * @throws IOException */ public static void copy(Reader reader, OutputStream output) throws IOException { // OutputStreamWriter writer = new OutputStreamWriter(output); // copy(reader, writer); OutputStreamWriter writer = null; try { writer = new OutputStreamWriter(output); copy(reader, writer); } finally { closeQuietly(writer); } } /** * 将字符输入流拷贝到字节输出流 * @param reader * @param output * @param encoding * @throws IOException */ public static void copy(Reader reader, OutputStream output, String encoding) throws IOException { // if (encoding == null) { // copy(reader, output); // } else { // OutputStreamWriter writer = new OutputStreamWriter(output, encoding); // copy(reader, writer); // } if (encoding == null) { copy(reader, output); } else { OutputStreamWriter writer = null; try { writer = new OutputStreamWriter(output, encoding); copy(reader, writer); } finally { closeQuietly(writer); } } } /** * 将字符输入流拷贝到字符输出流 * @param reader * @param writer * @return 字符数 * @throws IOException */ public static int copy(Reader reader, Writer writer) throws IOException { char[] buffer = new char[DEFAULT_BUFFER_SIZE]; int count = 0; int n = 0; while (-1 != (n = reader.read(buffer))) { writer.write(buffer, 0, n); count += n; } writer.flush(); return count; } /** * 关闭IO流 * @param close */ public static void closeQuietly(Closeable close) { closeQuietly(close, "关闭IO流出错!"); } /** * 关闭IO流 * @param close * @param errorMsg */ public static void closeQuietly(Closeable close, String errorMsg) { if (close != null) { try { close.close(); } catch (IOException e) { logger.error(errorMsg, e); } } }
public class PCIHttpClientImpl4 implements PCIHttpClient { private static LogUtils logger = new LogUtils(PCIHttpClientImpl4.class); private SSLConnectionSocketFactory sslSocketFactory = null; /** * 构造方法 * * <p>允许信任任何证书策略和允许任何域名验证</p> */ public PCIHttpClientImpl4() { this(false, false, true, true, null, null, null); } /** * 构造方法 * * @param allowAnyTrustMaterial 是否允许信任任何证书策略 * @param allowAnyHostnameVerifier 是否允许任何域名验证 */ public PCIHttpClientImpl4(boolean allowAnyTrustMaterial, boolean allowAnyHostnameVerifier) { this(false, false, allowAnyTrustMaterial, allowAnyHostnameVerifier, null, null, null); } /** * 构造方法 * * @param loadKeyMaterial 是否加载密钥 * @param loadTrustMaterial 是否加载信任证书 * @param keystoreFilePath 密钥库文件路径 * @param storePassword 密钥库密码 * @param keyPassword 私钥密码 */ public PCIHttpClientImpl4(boolean loadKeyMaterial, boolean loadTrustMaterial, String keystoreFilePath, String storePassword, String keyPassword) { this(loadKeyMaterial, loadTrustMaterial, false, true, keystoreFilePath, storePassword, keyPassword); } /** * 构造方法 * * @param loadKeyMaterial 是否加载密钥 * @param loadTrustMaterial 是否加载信任证书(若allowAnyTrustMaterial=true,则loadTrustMaterial无效) * @param allowAnyTrustMaterial 是否允许信任任何证书策略 * @param allowAnyHostnameVerifier 是否允许任何域名验证 * @param keystoreFilePath 密钥库文件路径 * @param storePassword 密钥库密码 * @param keyPassword 私钥密码 */ public PCIHttpClientImpl4(boolean loadKeyMaterial, boolean loadTrustMaterial, boolean allowAnyTrustMaterial, boolean allowAnyHostnameVerifier, String keystoreFilePath, String storePassword, String keyPassword) { try { // Create SSLContext SSLContextBuilder sslContextBuilder = new SSLContextBuilder(); if (loadKeyMaterial) { sslContextBuilder.loadKeyMaterial( new File(keystoreFilePath), storePassword.toCharArray(), keyPassword.toCharArray()); } if (allowAnyTrustMaterial) { sslContextBuilder.loadTrustMaterial(null, new AnyTrustStrategy()); } else if (loadTrustMaterial) { sslContextBuilder.loadTrustMaterial( new File(keystoreFilePath), storePassword.toCharArray(), new TrustSelfSignedStrategy()); } SSLContext sslContext = sslContextBuilder.build(); // Create SSLConnectionSocketFactory if (allowAnyHostnameVerifier) { sslSocketFactory = new SSLConnectionSocketFactory(sslContext, new AnyHostnameVerifier()); } else { sslSocketFactory = new SSLConnectionSocketFactory(sslContext); } } catch (NoSuchAlgorithmException e) { logger.error("Error occurred: NoSuchAlgorithmException", e); } catch (KeyStoreException e) { logger.error("Error occurred: KeyStoreException", e); } catch (UnrecoverableKeyException e) { logger.error("Error occurred: UnrecoverableKeyException", e); } catch (CertificateException e) { logger.error("Error occurred: CertificateException", e); } catch (IOException e) { logger.error("Error occurred: IOException", e); } catch (KeyManagementException e) { logger.error("Error occurred: KeyManagementException", e); } } /** * 信任任何证书策略 */ private static class AnyTrustStrategy implements TrustStrategy { @Override public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } } /** * 允许任何域名验证 */ private static class AnyHostnameVerifier implements HostnameVerifier { @Override public boolean verify(String hostname, SSLSession session) { return true; } } @Override public String sendGetAndResponseAsString(String url, int timeout) throws IOException { return sendGetAndResponseAsString(url, null, null, CustomConstants.CHARSET_UTF8, timeout); } @Override public String sendGetAndResponseAsString(String url, Map<String, String> headers, int timeout) throws IOException { return sendGetAndResponseAsString(url, headers, null, CustomConstants.CHARSET_UTF8, timeout); } @Override public String sendGetAndResponseAsString(String url, Map<String, String> headers, Map<String, String> params, String charsetName, int timeout) throws IOException { byte[] buffer = sendGetAndResponseAsByteArray(url, headers, params, charsetName, timeout); if (buffer == null) { return null; } return new String(buffer, charsetName); } @Override public byte[] sendGetAndResponseAsByteArray(String url, int timeout) throws IOException { return sendGetAndResponseAsByteArray(url, null, null, null, timeout); } @Override public byte[] sendGetAndResponseAsByteArray(String url, Map<String, String> headers, int timeout) throws IOException { return sendGetAndResponseAsByteArray(url, headers, null, null, timeout); } @Override public byte[] sendGetAndResponseAsByteArray(String url, Map<String, String> headers, Map<String, String> params, String charsetName, int timeout) throws IOException { ByteArrayOutputStream output = null; try { output = new ByteArrayOutputStream(); sendGet(url, headers, params, charsetName, timeout, output); return output.toByteArray(); } finally { IOUtils.closeQuietly(output); } } @Override public InputStream sendGetAndResponseAsStream(String url, Map<String, String> headers, Map<String, String> params, String charsetName, int timeout) throws IOException { byte[] buffer = sendGetAndResponseAsByteArray(url, headers, params, charsetName, timeout); if (buffer == null) { return null; } return new ByteArrayInputStream(buffer); } @Override public void sendGet(String url, Map<String, String> headers, Map<String, String> params, String charsetName, int timeout, OutputStream output) throws IOException { if (StringUtils.isEmpty(url)) { logger.error("The url can not be null."); throw new IllegalArgumentException("The url can not be null."); } sendAndResponseAsStream(new HttpGet(createURI(url, params, charsetName)), headers, timeout, output); } @Override public String sendPostAndResponseAsString(String url, Map<String, String> params, String charsetName, int timeout) throws IOException { return sendPostAndResponseAsString(url, null, params, null, charsetName, timeout); } @Override public String sendPostAndResponseAsString(String url, Map<String, String> headers, Map<String, String> params, int timeout, String charsetName) throws IOException { return sendPostAndResponseAsString(url, headers, params, null, charsetName, timeout); } @Override public String sendPostAndResponseAsString(String url, Map<String, String> headers, Object stringOrStream, String charsetName, int timeout) throws IOException { return sendPostAndResponseAsString(url, headers, null, stringOrStream, charsetName, timeout); } @Override public String sendPostAndResponseAsString(String url, Map<String, String> headers, Map<String, String> params, Object stringOrStream, String charsetName, int timeout) throws IOException { byte[] buffer = sendPostAndResponseAsByteArray( url, headers, params, stringOrStream, charsetName, timeout); if (buffer == null) { return null; } return new String(buffer, charsetName); } @Override public byte[] sendPostAndResponseAsByteArray(String url, Map<String, String> params, String charsetName, int timeout) throws IOException { return sendPostAndResponseAsByteArray(url, null, params, null, charsetName, timeout); } @Override public byte[] sendPostAndResponseAsByteArray(String url, Map<String, String> headers, Map<String, String> params, int timeout, String charsetName) throws IOException { return sendPostAndResponseAsByteArray(url, headers, params, null, charsetName, timeout); } @Override public byte[] sendPostAndResponseAsByteArray(String url, Map<String, String> headers, Object stringOrStream, String charsetName, int timeout) throws IOException { return sendPostAndResponseAsByteArray(url, headers, null, stringOrStream, charsetName, timeout); } @Override public byte[] sendPostAndResponseAsByteArray(String url, Map<String, String> headers, Map<String, String> params, Object stringOrStream, String charsetName, int timeout) throws IOException { ByteArrayOutputStream output = null; try { output = new ByteArrayOutputStream(); sendPost(url, headers, params, stringOrStream, charsetName, timeout, output); return output.toByteArray(); } finally { IOUtils.closeQuietly(output); } } @Override public InputStream sendPostAndResponseAsStream(String url, Map<String, String> headers, Map<String, String> params, Object stringOrStream, String charsetName, int timeout) throws IOException { byte[] buffer = sendPostAndResponseAsByteArray( url, headers, params, stringOrStream, charsetName, timeout); if (buffer == null) { return null; } return new ByteArrayInputStream(buffer); } @Override public void sendPost(String url, Map<String, String> headers, Map<String, String> params, Object stringOrStream, String charsetName, int timeout, OutputStream output) throws IOException { if (StringUtils.isEmpty(url)) { logger.error("The url can not be null."); throw new IllegalArgumentException("The url can not be null."); } // post请求方式 HttpPost method = new HttpPost(createURI(url, params, charsetName)); // 设置请求头信息 if (headers == null) { headers = new HashMap<String, String>(); } if (!headers.containsKey(CONTENT_TYPE)) { headers.put(CONTENT_TYPE, DEFAULT_CONTENTTYPE); } // 设置请求体内容 if (stringOrStream != null) { HttpEntity entity = null; if (stringOrStream instanceof InputStream) { entity = new InputStreamEntity((InputStream) stringOrStream); } else { entity = new StringEntity(stringOrStream.toString(), ContentType.create(CONTENT_TYPE, charsetName)); } method.setEntity(entity); } // 发送请求数据,并接收响应数据 sendAndResponseAsStream(method, headers, timeout, output); } /** * 发送请求数据,并接收响应数据 * @param method 请求方式 * @param headers 请求头信息 * @param timeout 超时时间 * @param output 响应内容(输出流) * @throws IOException */ private void sendAndResponseAsStream(HttpRequestBase method, Map<String, String> headers, int timeout, OutputStream output) throws IOException { // 设置请求配置信息 RequestConfig config = RequestConfig.custom() .setConnectTimeout(DEFAULT_CONNECTION_TIMEOUT) //连接超时时间 .setSocketTimeout(timeout) //读取超时时间 .setCircularRedirectsAllowed(true) //设置是否允许循环重定向(重定向到相同路径) .build(); method.setConfig(config); // 设置请求头信息 if (headers == null) { headers = new HashMap<String, String>(); } if (!headers.containsKey(USER_AGENT)) { headers.put(USER_AGENT, DEFAULT_USERAGENT); } for (Map.Entry<String, String> entry : headers.entrySet()) { method.setHeader(entry.getKey(), entry.getValue()); } // 发送请求 CloseableHttpClient httpClient = createHttpClient(method.getURI()); CloseableHttpResponse httpResponse = null; InputStream input = null; try { httpResponse = httpClient.execute(method); int status = httpResponse.getStatusLine().getStatusCode(); if (status != HttpStatus.SC_OK) { String errorMsg = CustomStringUtils.append("The remote service[", method.getURI(), "] respose an error status:", status); logger.error(errorMsg); if (status >= 500 && status < 600) { throw new IOException(errorMsg); } } HttpEntity httpEntity = httpResponse.getEntity(); if (httpEntity == null) { String errorMsg = CustomStringUtils.append("The remote service[", method.getURI(), "] respose entity is null. status:", status); logger.error(errorMsg); throw new IOException(errorMsg); } input = httpEntity.getContent(); if (input == null) { String errorMsg = CustomStringUtils.append("The remote service[", method.getURI(), "] respose entity content is null. status:", status); logger.error(errorMsg); throw new IOException(errorMsg); } IOUtils.copy(input, output); } catch (IOException e) { logger.error("Access to the remote service[" + method.getURI() + "] error.", e); throw e; } finally { IOUtils.closeQuietly(input); // method.releaseConnection(); IOUtils.closeQuietly(httpResponse); IOUtils.closeQuietly(httpClient); } } /** * 创建HttpClient对象 * @param uri * @return */ private CloseableHttpClient createHttpClient(URI uri) { if ("https".equalsIgnoreCase(uri.getScheme()) && sslSocketFactory != null) { return HttpClients.custom().setSSLSocketFactory(sslSocketFactory).build(); } else { return HttpClients.createDefault(); } } /** * 创建请求URI * @param url * @param params * @param charsetName * @return * @throws IOException */ private URI createURI(String url, Map<String, String> params, String charsetName) throws IOException { if (params == null || params.isEmpty()) { return URI.create(url); } // 设置请求参数 List<NameValuePair> parameters = new ArrayList<NameValuePair>(params.size()); for (Map.Entry<String, String> entry : params.entrySet()) { parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } try { return new URIBuilder(url) .addParameters(parameters) .setCharset(Charset.forName(charsetName)) .build(); } catch (URISyntaxException e) { String errorMsg = "Build request URI error, the url is [" + url + "]."; logger.error(errorMsg, e); throw new IOException(errorMsg, e); } } /** * @see PCIHttpClient.com.bestpay.pgw.tools.http.PGWHttpClient#sendGet(java.lang.String, java.util.Map, java.util.Map, java.lang.String, int) */ @Override public PCIHttpResponse sendGet(String url, Map<String, String> headers, Map<String, String> params, String charsetName, int timeout) throws IOException { if (StringUtils.isEmpty(url)) { logger.error("The url can not be null."); throw new IllegalArgumentException("The url can not be null."); } return sendAndResponseAsStream( new HttpGet(createURI(url, params, charsetName)), headers, timeout); } /** * @see PCIHttpClient.com.bestpay.pgw.tools.http.PGWHttpClient#sendPost(java.lang.String, java.util.Map, java.util.Map, java.lang.Object, java.lang.String, int) */ @Override public PCIHttpResponse sendPost(String url, Map<String, String> headers, Map<String, String> params, Object stringOrStream, String charsetName, int timeout) throws IOException { if (StringUtils.isEmpty(url)) { logger.error("The url can not be null."); throw new IllegalArgumentException("The url can not be null."); } // post请求方式 HttpPost method = new HttpPost(createURI(url, params, charsetName)); // 设置请求头信息 if (headers == null) { headers = new HashMap<String, String>(); } if (!headers.containsKey(CONTENT_TYPE)) { headers.put(CONTENT_TYPE, DEFAULT_CONTENTTYPE); } // 设置请求体内容 if (stringOrStream != null) { HttpEntity entity = null; if (stringOrStream instanceof InputStream) { entity = new InputStreamEntity((InputStream) stringOrStream); } else { entity = new StringEntity(stringOrStream.toString(), ContentType.create(CONTENT_TYPE, charsetName)); } method.setEntity(entity); } // 发送请求数据,并接收响应数据 return sendAndResponseAsStream(method, headers, timeout); } /** * 发送请求数据,并接收响应数据 * * @param method 请求方式 * @param headers 请求头信息 * @param timeout 超时时间 * @return * @throws IOException * * @since 2.0.0 */ private PCIHttpResponse sendAndResponseAsStream(HttpRequestBase method, Map<String, String> headers, int timeout) throws IOException { // 设置请求配置信息 RequestConfig config = RequestConfig.custom() .setConnectTimeout(DEFAULT_CONNECTION_TIMEOUT) //连接超时时间 .setSocketTimeout(timeout) //读取超时时间 .setCircularRedirectsAllowed(true) //设置是否允许循环重定向(重定向到相同路径) .build(); method.setConfig(config); // 设置请求头信息 if (headers == null) { headers = new HashMap<String, String>(); } if (!headers.containsKey(USER_AGENT)) { headers.put(USER_AGENT, DEFAULT_USERAGENT); } for (Map.Entry<String, String> entry : headers.entrySet()) { method.setHeader(entry.getKey(), entry.getValue()); } // 发送请求 CloseableHttpClient httpClient = createHttpClient(method.getURI()); CloseableHttpResponse httpResponse = null; InputStream responseBodyInputStream = null; ByteArrayOutputStream responseBodyOutputStream = null; try { httpResponse = httpClient.execute(method); int status = httpResponse.getStatusLine().getStatusCode(); if (status != HttpStatus.SC_OK) { String errorMsg = CustomStringUtils.append("The remote service[", method.getURI(), "] respose an error status:", status); logger.error(errorMsg); if (status >= 500 && status < 600) { throw new IOException(errorMsg); } } // 获取响应头 Map<String, String> responseHeaders = null; Header[] httpHeaders = httpResponse.getAllHeaders(); if (httpHeaders != null && httpHeaders.length > 0) { responseHeaders = new HashMap<String, String>(httpHeaders.length); for (Header header : httpHeaders) { responseHeaders.put(header.getName(), header.getValue()); } } // 获取响应体 byte[] responseBody = null; HttpEntity httpEntity = httpResponse.getEntity(); if (httpEntity != null) { responseBodyInputStream = httpEntity.getContent(); if (responseBodyInputStream != null) { responseBodyOutputStream = new ByteArrayOutputStream(); IOUtils.copy(responseBodyInputStream, responseBodyOutputStream); responseBody = responseBodyOutputStream.toByteArray(); } else { logger.warn(CustomStringUtils.append("The remote service[", method.getURI(), "] respose entity content is null. status:", status)); } } else { logger.warn(CustomStringUtils.append("The remote service[", method.getURI(), "] respose entity is null. status:", status)); } return new PCIHttpResponse(responseHeaders, responseBody); } catch (IOException e) { logger.error("Access to the remote service[" + method.getURI() + "] error.", e); throw e; } finally { IOUtils.closeQuietly(responseBodyInputStream); IOUtils.closeQuietly(responseBodyOutputStream); // method.releaseConnection(); IOUtils.closeQuietly(httpResponse); IOUtils.closeQuietly(httpClient); } } }
单元测试示例(本示例为双向认证示例,单向认证则对应修改PCIHttpClientImpl4的构造参数即可):
@Test public void testClock() throws Exception { String testUrl = "https://mail.xxxxxx.com:8440/service"; Map<String, String> map = new HashMap<String, String>(); map.put("messageType", "2058"); map.put("accessUser", "gxecard_test_user_zhengchuan"); map.put("terminalNo", "1"); String parameter = JSON.toJSONString(map); String requestJson = "parameter=" + parameter; System.out.println("requestJson:" + requestJson); // httpClient = new PCIHttpClientImpl4(true, false, // true, true, // "D:\\keystore.jks", "123456", "123456"); //证书可以是jks格式也可以是p12格式 httpClient = new PCIHttpClientImpl4(true, false, true, true, "D:\\keystore.p12", "123456", "123456"); PCIHttpResponse httpResponse = null; httpResponse = httpClient.sendPost(testUrl, null, null, requestJson, "UTF-8", 55 * 1000); System.out.println(httpResponse.getBodyString()); }