package com.ruoyi.common.utils.http;
|
|
import java.io.*;
|
import java.net.*;
|
import java.nio.charset.StandardCharsets;
|
import java.security.cert.X509Certificate;
|
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 org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import com.ruoyi.common.constant.Constants;
|
import com.ruoyi.common.utils.StringUtils;
|
import org.springframework.http.MediaType;
|
|
/**
|
* 通用http发送方法
|
*
|
* @author ruoyi
|
*/
|
public class HttpUtils
|
{
|
private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
|
|
public static final int DEFAULT_READ_TIMEOUT = 60000;
|
private static final String BOUNDARY_PREFIX = "----WebKitFormBoundary";
|
private static final String LINE_END = "\r\n";
|
private static final String TWO_HYPHENS = "--";
|
|
|
/**
|
* 生成唯一的boundary
|
*/
|
private static String generateBoundary() {
|
return BOUNDARY_PREFIX + System.currentTimeMillis();
|
}
|
|
/**
|
* 根据文件名获取Content-Type
|
*/
|
private static String getContentType(String fileName) {
|
if (fileName == null) {
|
return "application/octet-stream";
|
}
|
|
String extension = fileName.toLowerCase();
|
if (extension.endsWith(".jpg") || extension.endsWith(".jpeg")) {
|
return "image/jpeg";
|
} else if (extension.endsWith(".png")) {
|
return "image/png";
|
} else if (extension.endsWith(".gif")) {
|
return "image/gif";
|
} else if (extension.endsWith(".pdf")) {
|
return "application/pdf";
|
} else if (extension.endsWith(".doc")) {
|
return "application/msword";
|
} else if (extension.endsWith(".docx")) {
|
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
} else {
|
return "application/octet-stream";
|
}
|
}
|
|
/**
|
* 向指定 URL 发送GET方法的请求
|
*
|
* @param url 发送请求的 URL
|
* @return 所代表远程资源的响应结果
|
*/
|
public static String sendGet(String url)
|
{
|
return sendGet(url, StringUtils.EMPTY);
|
}
|
|
/**
|
* 向指定 URL 发送GET方法的请求
|
*
|
* @param url 发送请求的 URL
|
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
|
* @return 所代表远程资源的响应结果
|
*/
|
public static String sendGet(String url, String param)
|
{
|
return sendGet(url, param, Constants.UTF8);
|
}
|
|
/**
|
* 向指定 URL 发送GET方法的请求
|
*
|
* @param url 发送请求的 URL
|
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
|
* @param contentType 编码类型
|
* @return 所代表远程资源的响应结果
|
*/
|
public static String sendGet(String url, String param, String contentType)
|
{
|
StringBuilder result = new StringBuilder();
|
BufferedReader in = null;
|
try
|
{
|
String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
|
log.info("sendGet - {}", urlNameString);
|
URL realUrl = new URL(urlNameString);
|
URLConnection connection = realUrl.openConnection();
|
connection.setRequestProperty("accept", "*/*");
|
connection.setRequestProperty("connection", "Keep-Alive");
|
connection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
|
connection.connect();
|
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
|
String line;
|
while ((line = in.readLine()) != null)
|
{
|
result.append(line);
|
}
|
log.info("recv - {}", result);
|
}
|
catch (ConnectException e)
|
{
|
log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
|
}
|
catch (SocketTimeoutException e)
|
{
|
log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
|
}
|
catch (IOException e)
|
{
|
log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
|
}
|
catch (Exception e)
|
{
|
log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
|
}
|
finally
|
{
|
try
|
{
|
if (in != null)
|
{
|
in.close();
|
}
|
}
|
catch (Exception ex)
|
{
|
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
|
}
|
}
|
return result.toString();
|
}
|
|
/**
|
* 向指定 URL 发送POST方法的请求
|
*
|
* @param url 发送请求的 URL
|
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
|
* @return 所代表远程资源的响应结果
|
*/
|
public static String sendPost(String url, String param)
|
{
|
return sendPost(url, param, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
|
}
|
|
/**
|
* 向指定 URL 发送POST方法的请求
|
*
|
* @param url 发送请求的 URL
|
* @param param 请求参数
|
* @param contentType 内容类型
|
* @return 所代表远程资源的响应结果
|
*/
|
public static String sendPost(String url, String param, String contentType)
|
{
|
PrintWriter out = null;
|
BufferedReader in = null;
|
StringBuilder result = new StringBuilder();
|
try
|
{
|
log.info("sendPost - {}", url);
|
URL realUrl = new URL(url);
|
URLConnection conn = realUrl.openConnection();
|
|
//设置连接超时时间
|
// conn.setConnectTimeout(DEFAULT_READ_TIMEOUT);
|
// //设置读取超时时间
|
// conn.setReadTimeout(DEFAULT_READ_TIMEOUT);
|
|
conn.setRequestProperty("accept", "*/*");
|
conn.setRequestProperty("connection", "Keep-Alive");
|
conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
|
conn.setRequestProperty("Accept-Charset", "utf-8");
|
conn.setRequestProperty("Content-Type", contentType);
|
conn.setDoOutput(true);
|
conn.setDoInput(true);
|
out = new PrintWriter(conn.getOutputStream());
|
out.print(param);
|
out.flush();
|
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
|
String line;
|
while ((line = in.readLine()) != null)
|
{
|
result.append(line);
|
}
|
log.info("recv - {}", result);
|
}
|
catch (ConnectException e)
|
{
|
log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
|
}
|
catch (SocketTimeoutException e)
|
{
|
log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
|
}
|
catch (IOException e)
|
{
|
log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
|
}
|
catch (Exception e)
|
{
|
log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
|
}
|
finally
|
{
|
try
|
{
|
if (out != null)
|
{
|
out.close();
|
}
|
if (in != null)
|
{
|
in.close();
|
}
|
}
|
catch (IOException ex)
|
{
|
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
|
}
|
}
|
return result.toString();
|
}
|
|
public static String sendSSLPost(String url, String param)
|
{
|
return sendSSLPost(url, param, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
|
}
|
|
public static String sendSSLPost(String url, String param, String contentType)
|
{
|
StringBuilder result = new StringBuilder();
|
String urlNameString = url + "?" + param;
|
try
|
{
|
// log.info("sendSSLPost - {}", urlNameString);
|
SSLContext sc = SSLContext.getInstance("SSL");
|
sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
|
URL console = new URL(urlNameString);
|
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
|
conn.setRequestProperty("accept", "*/*");
|
conn.setRequestProperty("connection", "Keep-Alive");
|
conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
|
conn.setRequestProperty("Accept-Charset", "utf-8");
|
conn.setRequestProperty("Content-Type", contentType);
|
conn.setDoOutput(true);
|
conn.setDoInput(true);
|
|
conn.setSSLSocketFactory(sc.getSocketFactory());
|
conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
|
conn.connect();
|
InputStream is = conn.getInputStream();
|
BufferedReader br = new BufferedReader(new InputStreamReader(is));
|
String ret = "";
|
while ((ret = br.readLine()) != null)
|
{
|
if (ret != null && !"".equals(ret.trim()))
|
{
|
result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
|
}
|
}
|
// log.info("recv - {}", result);
|
conn.disconnect();
|
br.close();
|
}
|
catch (ConnectException e)
|
{
|
// log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
|
}
|
catch (SocketTimeoutException e)
|
{
|
// log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
|
}
|
catch (IOException e)
|
{
|
// log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
|
}
|
catch (Exception e)
|
{
|
|
// log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
|
}
|
return result.toString();
|
}
|
|
private static class TrustAnyTrustManager implements X509TrustManager
|
{
|
@Override
|
public void checkClientTrusted(X509Certificate[] chain, String authType)
|
{
|
}
|
|
@Override
|
public void checkServerTrusted(X509Certificate[] chain, String authType)
|
{
|
}
|
|
@Override
|
public X509Certificate[] getAcceptedIssuers()
|
{
|
return new X509Certificate[] {};
|
}
|
}
|
|
private static class TrustAnyHostnameVerifier implements HostnameVerifier
|
{
|
@Override
|
public boolean verify(String hostname, SSLSession session)
|
{
|
return true;
|
}
|
}
|
|
/**
|
* 发送文件上传请求
|
*
|
* @param url 请求URL
|
* @param params 请求参数(包含文件流)
|
* @return 响应内容
|
*/
|
public static String postFile(String url, Map<String, Object> params) {
|
return postFile(url, params, null);
|
}
|
|
/**
|
* 发送文件上传请求(支持自定义文件名)
|
* 支持HTTP和HTTPS,HTTPS会自动忽略SSL证书验证
|
*
|
* @param url 请求URL
|
* @param params 请求参数(包含文件流)
|
* @param fileName 文件名(可选,如果为null则使用参数键名)
|
* @return 响应内容
|
*/
|
public static String postFile(String url, Map<String, Object> params, String fileName) {
|
HttpURLConnection connection = null;
|
try {
|
// 生成唯一的boundary
|
String boundary = generateBoundary();
|
|
log.info("开始文件上传 - URL: {}, fileName: {}, boundary: {}", url, fileName, boundary);
|
log.info("参数数量: {}", params.size());
|
for (Map.Entry<String, Object> entry : params.entrySet()) {
|
log.info("参数: {} = {}", entry.getKey(), entry.getValue() instanceof InputStream ? "InputStream" : entry.getValue());
|
}
|
|
// 创建连接
|
URL requestUrl = new URL(url);
|
connection = (HttpURLConnection) requestUrl.openConnection();
|
|
// 如果是HTTPS请求,配置SSL信任所有证书
|
if (connection instanceof HttpsURLConnection) {
|
HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;
|
SSLContext sc = SSLContext.getInstance("TLS");
|
sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
|
httpsConnection.setSSLSocketFactory(sc.getSocketFactory());
|
httpsConnection.setHostnameVerifier(new TrustAnyHostnameVerifier());
|
log.info("配置HTTPS连接,忽略SSL证书验证");
|
}
|
|
|
// 设置请求属性
|
connection.setRequestMethod("POST");
|
connection.setDoOutput(true);
|
connection.setDoInput(true);
|
connection.setUseCaches(false);
|
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
|
connection.setRequestProperty("Accept", "application/json");
|
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
connection.setRequestProperty("Connection", "Keep-Alive");
|
connection.setRequestProperty("Accept-Charset", "utf-8");
|
connection.setConnectTimeout(30000);
|
connection.setReadTimeout(60000);
|
|
// 构建请求体
|
try (OutputStream outputStream = connection.getOutputStream();
|
PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8), true)) {
|
|
// 写入普通参数
|
for (Map.Entry<String, Object> entry : params.entrySet()) {
|
Object value = entry.getValue();
|
if (!(value instanceof InputStream)) {
|
writer.append(TWO_HYPHENS).append(boundary).append(LINE_END);
|
writer.append("Content-Disposition: form-data; name=\"").append(entry.getKey()).append("\"").append(LINE_END);
|
writer.append("Content-Type: text/plain; charset=UTF-8").append(LINE_END);
|
writer.append(LINE_END);
|
writer.append(value.toString()).append(LINE_END);
|
writer.flush();
|
}
|
}
|
|
// 写入文件参数
|
for (Map.Entry<String, Object> entry : params.entrySet()) {
|
Object value = entry.getValue();
|
if (value instanceof InputStream) {
|
// 确定文件名
|
String actualFileName = fileName != null ? fileName : entry.getKey();
|
|
writer.append(TWO_HYPHENS).append(boundary).append(LINE_END);
|
writer.append("Content-Disposition: form-data; name=\"").append(entry.getKey()).append("\"; filename=\"").append(actualFileName).append("\"").append(LINE_END);
|
writer.append("Content-Type: ").append(getContentType(actualFileName)).append(LINE_END);
|
writer.append(LINE_END);
|
writer.flush();
|
|
// 写入文件内容
|
try (InputStream inputStream = (InputStream) value) {
|
byte[] buffer = new byte[4096];
|
int bytesRead;
|
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
outputStream.write(buffer, 0, bytesRead);
|
}
|
outputStream.flush();
|
}
|
|
writer.append(LINE_END);
|
writer.flush();
|
}
|
}
|
|
// 写入结束标记
|
writer.append(TWO_HYPHENS).append(boundary).append(TWO_HYPHENS).append(LINE_END);
|
writer.flush();
|
}
|
|
// 获取响应
|
int responseCode = connection.getResponseCode();
|
log.info("文件上传响应码:{}", responseCode);
|
|
// 读取响应内容
|
StringBuilder response = new StringBuilder();
|
try (BufferedReader reader = new BufferedReader(
|
new InputStreamReader(
|
responseCode == HttpURLConnection.HTTP_OK ?
|
connection.getInputStream() :
|
connection.getErrorStream(),
|
StandardCharsets.UTF_8))) {
|
String line;
|
while ((line = reader.readLine()) != null) {
|
response.append(line);
|
}
|
}
|
|
if (responseCode != HttpURLConnection.HTTP_OK) {
|
log.error("文件上传失败,响应码:{},响应内容:{}", responseCode, response.toString());
|
throw new RuntimeException("文件上传失败,响应码: " + responseCode + ",响应内容: " + response.toString());
|
}
|
|
log.info("文件上传成功,响应:{}", response.toString());
|
return response.toString();
|
|
} catch (Exception e) {
|
log.error("文件上传异常:{}", e.getMessage(), e);
|
throw new RuntimeException("文件上传失败: " + e.getMessage(), e);
|
} finally {
|
if (connection != null) {
|
connection.disconnect();
|
}
|
}
|
}
|
}
|