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 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 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 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 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 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(); } } } }