| | |
| | | package com.ruoyi.common.utils.http; |
| | | |
| | | import java.io.BufferedReader; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.io.InputStreamReader; |
| | | import java.io.PrintWriter; |
| | | import java.net.ConnectException; |
| | | import java.net.SocketTimeoutException; |
| | | import java.net.URL; |
| | | import java.net.URLConnection; |
| | | 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; |
| | |
| | | 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方法的请求 |
| | |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 发送文件上传请求 |
| | | * |
| | | * @param url 请求URL |
| | | * @param params 请求参数(包含文件流) |
| | | * @return 响应内容 |
| | | */ |
| | | public static String postFile(String url, Map<String, Object> params) { |
| | | return postFile(url, params, null); |
| | | } |
| | | |
| | | /** |
| | | * 发送文件上传请求(支持自定义文件名) |
| | | * |
| | | * @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(); |
| | | |
| | | // 设置请求属性 |
| | | 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(); |
| | | } |
| | | } |
| | | } |
| | | } |