自写https请求工具
import com.alibaba.druid.support.json.JSONUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
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 java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Random;
/**
* https工具
*
* @author [email protected]
* @version 1.0
* @since 2020/3/2 6:36 PM
*/
@Slf4j
public class HttpsUtils {
private HttpsUtils() {
}
/**
* 将url中的协议改为https
*/
public static String convertUrl2Https(String url) {
if (StringUtils.isEmpty(url)) {
return "";
}
return url.replaceFirst("^(?:http:)?//", "https://");
}
/**
* 发起https请求
*
* @param url 带参数的url, 比如https://www.xxx.com?a=1
* @param params 需要放在body中的参数,最终会转化为json格式传递
* @param timeout 超时时间,单位是毫秒。
* @return 请求返回的结果,json格式
*/
public static String doHttps(String url, Map params, int timeout) {
// 返回的结果
StringBuilder result = new StringBuilder();
String sendString =JSONUtils.toJSONString(params);
log.info("do https request. url:{}, params:{}, timeout:{}", url, params, timeout);
HttpsURLConnection urlCon = getHttpsUrlConn(url, true, timeout);
if (urlCon == null) {
return null;
}
BufferedReader in = null;
OutputStream os = null;
try {
// 获取URLConnection对象对应的输出流
os = urlCon.getOutputStream();
//参数是键值队,放在请求的body当中
os.write(sendString.getBytes());
os.flush();
// 发送请求参数
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(urlCon.getInputStream(), "UTF-8"));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
} catch (Exception e) {
log.error("do https fail . url:{}, params:{}, timeout:{}, e:{}", url, params, timeout, e);
return null;
} finally {// 使用finally块来关闭输出流、输入流
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(os);
urlCon.disconnect();
}
log.info("do https request. url:{}, params:{}, timeout:{}, result:{}", url, params, timeout, result);
return result.toString();
}
/**
* 获取https连接实例
*
* @param url 请求的url,以https开头
* @param isPost 为true代表使用post请求,为false代表使用get请求
* @param timeout 超时时间
* @return
*/
public static HttpsURLConnection getHttpsUrlConn(String url, boolean isPost, Integer timeout) {
HttpsURLConnection urlCon;
try {
// 返回指定协议的 SSLContext 对象
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
// 初始化上下文
sslContext.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new SecureRandom());
URL url2 = new URL(url);
urlCon = (HttpsURLConnection) url2.openConnection();
/*
* 设置信任凭据,这里方法体为空,所以任何https的链接都不需要验证证书
* 这一步的原因: 当访问HTTPS的网址。您可能已经安装了服务器证书到您的JRE的keystore
* 但是服务器的名称与证书实际域名不相等。这通常发生在你使用的是非标准网上签发的证书。
*
* 解决方法:让JRE相信所有的证书和对系统的域名和证书域名。
*
* 如果少了这一步会报错:java.io.IOException: HTTPS hostname wrong: should be
*/
urlCon.setHostnameVerifier(new TrustAnyHostnameVerifier());
//默认是get请求
if (isPost) {
urlCon.setRequestMethod("POST");
}
urlCon.setRequestProperty("Content-type", "application/json;charset=UTF-8");
if (timeout != null) {
//设置超时时间
urlCon.setConnectTimeout(timeout);
urlCon.setReadTimeout(timeout);
}
// 发送POST请求必须设置如下两行, get请求可以设置
urlCon.setDoOutput(true);
urlCon.setDoInput(true);
urlCon.setUseCaches(false);
// 设置当前实例使用的SSLSoctetFactory
urlCon.setSSLSocketFactory(sslContext.getSocketFactory());
} catch (Exception e) {
log.error("getHttpsUrlConn fail. url:{}, timeout:{}, e:{}", url, timeout, e);
return null;
}
return urlCon;
}
/**
* 获取url中的文件名
*
* @param url https格式的url
* @return 文件名
*/
public static String getFileName(String url) {
String[] arr1 = url.split("/");
String fileName = "";
if (arr1.length > 0) {
fileName = arr1[arr1.length - 1];
}
return fileName;
}
/**
* 根据https链接下载文件
*
* @param urlStr https开头的链接
* @param fileName 下载之后的文件名
* @param savePath 文件保存的路径
* @return 返回下载好的文件的全路径
*/
public static String downLoadFromUrlHttps(String urlStr, String fileName,
String savePath) {
// 文件保存位置
File saveDir = new File(savePath);
if (!saveDir.exists()) {
saveDir.mkdirs();
}
File file = new File(saveDir + File.separator + getRandomStr() + fileName);
HttpsURLConnection conn = HttpsUtils.getHttpsUrlConn(urlStr, false, null);
if (conn == null) {
log.error("downLoadFromUrlHttps get HttpsURLConnection fail. url:{}, fileName:{}, savePath:{}",
urlStr, fileName, savePath);
return null;
}
try (InputStream inputStream = conn.getInputStream();
FileOutputStream fileOutputStream = new FileOutputStream(file)) {
IOUtils.copyLarge(inputStream, fileOutputStream);
return file.getAbsolutePath();
} catch (Exception e) {
log.error("downLoadFromUrlHttps fail. url:{}, fileName:{}, savePath:{}, e:{}",
urlStr, fileName, savePath, e);
return null;
} finally {
conn.disconnect();
}
}
/**
* 生成长度为6的随机字符串
*
* @return 生成的字符串
*/
private static String getRandomStr() {
return "LAN" + getRandomInt(100, 999);
}
private static int getRandomInt(int min, int max) {
return new Random().nextInt(max) % (max - min + 1) + min;
}
/**
* 删除文件
*
* @param absolutePath 文件的绝对路径
*/
public static void deleteFile(String absolutePath) {
try {
Files.delete(Paths.get(new File(absolutePath).getPath()));
} catch (IOException e) {
log.error("delete file fail. absolutePath:{}", absolutePath);
}
}
/**
* 里面的方法都是空的,当方法为空是默认为所有的链接都为安全,也就是所有的链接都能够访问到 当然这样有一定的安全风险,可以根据实际需要写入内容
*/
public static class TrustAnyTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
//https信任验证
log.info("this method never throws exception, it means trust any client");
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
//https信任验证
log.info("this method never throws exception, it means trust any client");
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
/**
* 校验https网址是否安全
*/
public static class TrustAnyHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
//直接返回true,默认所有https请求都是安全的,也就是说不校验证书的正确性
return StringUtils.isNotEmpty(hostname);
}
}
}