001/* 002 * Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.audit.http; 017 018import com.mybatisflex.core.util.StringUtil; 019import org.apache.ibatis.logging.LogFactory; 020 021import javax.net.ssl.*; 022import java.io.IOException; 023import java.io.InputStreamReader; 024import java.io.OutputStream; 025import java.io.UnsupportedEncodingException; 026import java.net.*; 027import java.security.KeyManagementException; 028import java.security.NoSuchAlgorithmException; 029import java.security.NoSuchProviderException; 030import java.security.cert.CertificateException; 031import java.security.cert.X509Certificate; 032import java.util.Enumeration; 033import java.util.Map; 034import java.util.Map.Entry; 035 036/** 037 * Http 工具类。 038 */ 039public class HttpUtil { 040 041 private HttpUtil() { 042 } 043 044 private static final String POST = "POST"; 045 046 private static String CHARSET = "UTF-8"; 047 private static int connectTimeout = 15000; // 连接超时,单位毫秒 048 private static int readTimeout = 15000; // 读取超时,单位毫秒 049 050 private static final SSLSocketFactory sslSocketFactory = initSSLSocketFactory(); 051 052 private static final TrustAnyHostnameVerifier trustAnyHostnameVerifier = new TrustAnyHostnameVerifier(); 053 054 public static String getHostIp() { 055 try { 056 for (Enumeration<NetworkInterface> net = NetworkInterface.getNetworkInterfaces(); net.hasMoreElements(); ) { 057 NetworkInterface networkInterface = net.nextElement(); 058 if (networkInterface.isLoopback() || networkInterface.isVirtual() || !networkInterface.isUp()) { 059 continue; 060 } 061 for (Enumeration<InetAddress> addrs = networkInterface.getInetAddresses(); addrs.hasMoreElements(); ) { 062 InetAddress addr = addrs.nextElement(); 063 if (addr instanceof Inet4Address) { 064 return addr.getHostAddress(); 065 } 066 } 067 } 068 } catch (Exception e) { 069 // ignore 070 } 071 return "127.0.0.1"; 072 } 073 074 /** 075 * https 域名校验 076 */ 077 private static class TrustAnyHostnameVerifier implements HostnameVerifier { 078 079 @Override 080 public boolean verify(String hostname, SSLSession session) { 081 return true; 082 } 083 084 } 085 086 /** 087 * https 证书管理 088 */ 089 private static class TrustAnyTrustManager implements X509TrustManager { 090 091 @Override 092 public X509Certificate[] getAcceptedIssuers() { 093 return null; 094 } 095 096 @Override 097 public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 098 } 099 100 @Override 101 public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 102 } 103 104 } 105 106 107 private static SSLSocketFactory initSSLSocketFactory() { 108 try { 109 TrustManager[] tm = {new HttpUtil.TrustAnyTrustManager()}; 110 SSLContext sslContext = SSLContext.getInstance("TLS"); // "TLS", "SunJSSE" 111 sslContext.init(null, tm, new java.security.SecureRandom()); 112 return sslContext.getSocketFactory(); 113 } catch (Exception e) { 114 throw new RuntimeException(e); 115 } 116 } 117 118 public static void setCharSet(String charSet) { 119 if (StringUtil.isBlank(charSet)) { 120 throw new IllegalArgumentException("charSet can not be blank."); 121 } 122 HttpUtil.CHARSET = charSet; 123 } 124 125 public static void setConnectTimeout(int connectTimeout) { 126 HttpUtil.connectTimeout = connectTimeout; 127 } 128 129 public static void setReadTimeout(int readTimeout) { 130 HttpUtil.readTimeout = readTimeout; 131 } 132 133 private static HttpURLConnection getHttpConnection(String url, String method, Map<String, String> headers) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException { 134 URL _url = new URL(url); 135 HttpURLConnection conn = (HttpURLConnection) _url.openConnection(); 136 if (conn instanceof HttpsURLConnection) { 137 ((HttpsURLConnection) conn).setSSLSocketFactory(sslSocketFactory); 138 ((HttpsURLConnection) conn).setHostnameVerifier(trustAnyHostnameVerifier); 139 } 140 141 conn.setRequestMethod(method); 142 conn.setDoOutput(true); 143 conn.setDoInput(true); 144 145 conn.setConnectTimeout(connectTimeout); 146 conn.setReadTimeout(readTimeout); 147 148 conn.setRequestProperty("Content-Type", "application/json; charset=utf-8"); 149 150 if (headers != null && !headers.isEmpty()) { 151 for (Entry<String, String> entry : headers.entrySet()) { 152 conn.setRequestProperty(entry.getKey(), entry.getValue()); 153 } 154 } 155 156 return conn; 157 } 158 159 160 /** 161 * Send POST request 162 */ 163 public static String post(String url, Map<String, String> queryParas, String data, Map<String, String> headers) { 164 HttpURLConnection conn = null; 165 try { 166 conn = getHttpConnection(buildUrlQuery(url, queryParas), POST, headers); 167 conn.connect(); 168 169 if (data != null) { 170 try (OutputStream out = conn.getOutputStream()) { 171 out.write(data.getBytes(CHARSET)); 172 out.flush(); 173 } 174 } 175 return readString(conn); 176 } catch (IOException e) { 177 LogFactory.getLog(HttpUtil.class).error("post error.", e); 178 return null; 179 } catch (Exception e) { 180 throw new RuntimeException(e); 181 } finally { 182 if (conn != null) { 183 conn.disconnect(); 184 } 185 } 186 } 187 188 public static String post(String url, Map<String, String> queryParas, String data) { 189 return post(url, queryParas, data, null); 190 } 191 192 public static String post(String url, String data, Map<String, String> headers) { 193 return post(url, null, data, headers); 194 } 195 196 public static String post(String url, String data) { 197 return post(url, null, data, null); 198 } 199 200 private static String readString(HttpURLConnection conn) throws IOException { 201 try (InputStreamReader isr = new InputStreamReader(conn.getInputStream(), CHARSET)) { 202 StringBuilder ret = new StringBuilder(); 203 char[] buf = new char[1024]; 204 for (int num; (num = isr.read(buf, 0, buf.length)) != -1; ) { 205 ret.append(buf, 0, num); 206 } 207 return ret.toString(); 208 } 209 } 210 211 212 private static String buildUrlQuery(String url, Map<String, String> queryParas) { 213 if (queryParas == null || queryParas.isEmpty()) { 214 return url; 215 } 216 217 StringBuilder sb = new StringBuilder(url); 218 boolean isFirst; 219 if (url.indexOf('?') == -1) { 220 isFirst = true; 221 sb.append('?'); 222 } else { 223 isFirst = false; 224 } 225 226 for (Entry<String, String> entry : queryParas.entrySet()) { 227 if (isFirst) { 228 isFirst = false; 229 } else { 230 sb.append('&'); 231 } 232 233 String key = entry.getKey(); 234 String value = entry.getValue(); 235 if (StringUtil.isNotBlank(value)) { 236 try { 237 value = URLEncoder.encode(value, CHARSET); 238 } catch (UnsupportedEncodingException e) { 239 throw new RuntimeException(e); 240 } 241 } 242 sb.append(key).append('=').append(value); 243 } 244 return sb.toString(); 245 } 246 247 248} 249 250 251 252 253 254