关于证书
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());
}