|
|
|
@ -0,0 +1,264 @@ |
|
|
|
package org.jeecg.api.wxUtils; |
|
|
|
|
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
import org.apache.http.HttpStatus; |
|
|
|
import org.apache.http.client.config.RequestConfig; |
|
|
|
import org.apache.http.client.methods.CloseableHttpResponse; |
|
|
|
import org.apache.http.client.methods.HttpGet; |
|
|
|
import org.apache.http.client.methods.HttpPost; |
|
|
|
import org.apache.http.client.utils.URIBuilder; |
|
|
|
import org.apache.http.conn.ssl.SSLConnectionSocketFactory; |
|
|
|
import org.apache.http.conn.ssl.SSLContextBuilder; |
|
|
|
import org.apache.http.conn.ssl.TrustStrategy; |
|
|
|
import org.apache.http.entity.StringEntity; |
|
|
|
import org.apache.http.impl.client.CloseableHttpClient; |
|
|
|
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; |
|
|
|
import org.apache.http.impl.client.HttpClients; |
|
|
|
import org.apache.http.util.EntityUtils; |
|
|
|
|
|
|
|
import javax.net.ssl.SSLContext; |
|
|
|
import java.io.IOException; |
|
|
|
import java.net.URI; |
|
|
|
import java.security.KeyManagementException; |
|
|
|
import java.security.KeyStoreException; |
|
|
|
import java.security.NoSuchAlgorithmException; |
|
|
|
import java.security.cert.CertificateException; |
|
|
|
import java.security.cert.X509Certificate; |
|
|
|
import java.util.Map; |
|
|
|
|
|
|
|
/** |
|
|
|
* 微信API专用HTTP客户端工具类 |
|
|
|
* 具有超时配置、重试机制和异常处理 |
|
|
|
* |
|
|
|
* @author system |
|
|
|
* @date 2025-01-25 |
|
|
|
*/ |
|
|
|
@Slf4j |
|
|
|
public class WxHttpClientUtil { |
|
|
|
|
|
|
|
// 超时配置常量 |
|
|
|
private static final int CONNECTION_REQUEST_TIMEOUT = 10000; // 10秒 |
|
|
|
private static final int CONNECT_TIMEOUT = 15000; // 15秒 |
|
|
|
private static final int SOCKET_TIMEOUT = 30000; // 30秒 |
|
|
|
private static final int MAX_RETRY_COUNT = 3; // 最大重试次数 |
|
|
|
|
|
|
|
/** |
|
|
|
* 创建带超时配置的SSL客户端 |
|
|
|
*/ |
|
|
|
private static CloseableHttpClient createWxHttpClient() { |
|
|
|
try { |
|
|
|
// SSL配置 - 信任所有证书 |
|
|
|
SSLContext sslContext = new SSLContextBuilder() |
|
|
|
.loadTrustMaterial(null, new TrustStrategy() { |
|
|
|
@Override |
|
|
|
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { |
|
|
|
return true; |
|
|
|
} |
|
|
|
}).build(); |
|
|
|
|
|
|
|
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( |
|
|
|
sslContext, |
|
|
|
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER |
|
|
|
); |
|
|
|
|
|
|
|
// 请求配置 |
|
|
|
RequestConfig requestConfig = RequestConfig.custom() |
|
|
|
.setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT) |
|
|
|
.setConnectTimeout(CONNECT_TIMEOUT) |
|
|
|
.setSocketTimeout(SOCKET_TIMEOUT) |
|
|
|
.build(); |
|
|
|
|
|
|
|
// 重试处理器 |
|
|
|
DefaultHttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(MAX_RETRY_COUNT, true); |
|
|
|
|
|
|
|
return HttpClients.custom() |
|
|
|
.setSSLSocketFactory(sslsf) |
|
|
|
.setDefaultRequestConfig(requestConfig) |
|
|
|
.setRetryHandler(retryHandler) |
|
|
|
.build(); |
|
|
|
|
|
|
|
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { |
|
|
|
log.error("创建SSL客户端失败: {}", e.getMessage(), e); |
|
|
|
// 返回默认客户端作为后备 |
|
|
|
return HttpClients.createDefault(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 执行GET请求(微信API专用) |
|
|
|
* @param url 请求URL |
|
|
|
* @param params 请求参数 |
|
|
|
* @return 响应字符串 |
|
|
|
*/ |
|
|
|
public static String doGet(String url, Map<String, String> params) { |
|
|
|
return doGetWithRetry(url, params, 0); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 执行GET请求(微信API专用) |
|
|
|
* @param url 请求URL |
|
|
|
* @return 响应字符串 |
|
|
|
*/ |
|
|
|
public static String doGet(String url) { |
|
|
|
return doGet(url, null); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 带重试机制的GET请求 |
|
|
|
*/ |
|
|
|
private static String doGetWithRetry(String url, Map<String, String> params, int retryCount) { |
|
|
|
CloseableHttpClient httpClient = null; |
|
|
|
CloseableHttpResponse response = null; |
|
|
|
|
|
|
|
try { |
|
|
|
log.info("开始请求微信API: {}, 重试次数: {}", url, retryCount); |
|
|
|
|
|
|
|
httpClient = createWxHttpClient(); |
|
|
|
|
|
|
|
// 构建URI |
|
|
|
URIBuilder builder = new URIBuilder(url); |
|
|
|
if (params != null) { |
|
|
|
for (Map.Entry<String, String> entry : params.entrySet()) { |
|
|
|
builder.addParameter(entry.getKey(), entry.getValue()); |
|
|
|
} |
|
|
|
} |
|
|
|
URI uri = builder.build(); |
|
|
|
|
|
|
|
// 创建GET请求 |
|
|
|
HttpGet httpGet = new HttpGet(uri); |
|
|
|
httpGet.setHeader("User-Agent", "WxHttpClient/1.0"); |
|
|
|
httpGet.setHeader("Accept", "application/json, text/plain, */*"); |
|
|
|
|
|
|
|
// 执行请求 |
|
|
|
response = httpClient.execute(httpGet); |
|
|
|
|
|
|
|
// 检查响应状态 |
|
|
|
int statusCode = response.getStatusLine().getStatusCode(); |
|
|
|
if (statusCode == HttpStatus.SC_OK) { |
|
|
|
String result = EntityUtils.toString(response.getEntity(), "UTF-8"); |
|
|
|
log.info("微信API请求成功: {}", url); |
|
|
|
return result; |
|
|
|
} else { |
|
|
|
log.warn("微信API返回非200状态码: {}, URL: {}", statusCode, url); |
|
|
|
throw new RuntimeException("HTTP状态码异常: " + statusCode); |
|
|
|
} |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
log.error("微信API请求失败: {}, 错误: {}, 重试次数: {}", url, e.getMessage(), retryCount); |
|
|
|
|
|
|
|
// 如果还有重试机会,进行重试 |
|
|
|
if (retryCount < MAX_RETRY_COUNT) { |
|
|
|
log.info("准备进行第{}次重试...", retryCount + 1); |
|
|
|
try { |
|
|
|
Thread.sleep(1000 * (retryCount + 1)); // 递增延迟 |
|
|
|
} catch (InterruptedException ie) { |
|
|
|
Thread.currentThread().interrupt(); |
|
|
|
} |
|
|
|
return doGetWithRetry(url, params, retryCount + 1); |
|
|
|
} |
|
|
|
|
|
|
|
// 重试次数用尽,抛出异常 |
|
|
|
throw new RuntimeException("微信API请求失败,已重试" + MAX_RETRY_COUNT + "次: " + e.getMessage(), e); |
|
|
|
|
|
|
|
} finally { |
|
|
|
// 关闭资源 |
|
|
|
if (response != null) { |
|
|
|
try { |
|
|
|
response.close(); |
|
|
|
} catch (IOException e) { |
|
|
|
log.error("关闭响应失败: {}", e.getMessage()); |
|
|
|
} |
|
|
|
} |
|
|
|
if (httpClient != null) { |
|
|
|
try { |
|
|
|
httpClient.close(); |
|
|
|
} catch (IOException e) { |
|
|
|
log.error("关闭客户端失败: {}", e.getMessage()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 执行POST请求(微信API专用) |
|
|
|
* @param url 请求URL |
|
|
|
* @param jsonBody JSON请求体 |
|
|
|
* @return 响应字符串 |
|
|
|
*/ |
|
|
|
public static String doPost(String url, String jsonBody) { |
|
|
|
return doPostWithRetry(url, jsonBody, 0); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 带重试机制的POST请求 |
|
|
|
*/ |
|
|
|
private static String doPostWithRetry(String url, String jsonBody, int retryCount) { |
|
|
|
CloseableHttpClient httpClient = null; |
|
|
|
CloseableHttpResponse response = null; |
|
|
|
|
|
|
|
try { |
|
|
|
log.info("开始POST请求微信API: {}, 重试次数: {}", url, retryCount); |
|
|
|
|
|
|
|
httpClient = createWxHttpClient(); |
|
|
|
|
|
|
|
// 创建POST请求 |
|
|
|
HttpPost httpPost = new HttpPost(url); |
|
|
|
httpPost.setHeader("Content-Type", "application/json; charset=UTF-8"); |
|
|
|
httpPost.setHeader("User-Agent", "WxHttpClient/1.0"); |
|
|
|
|
|
|
|
// 设置请求体 |
|
|
|
if (jsonBody != null) { |
|
|
|
StringEntity entity = new StringEntity(jsonBody, "UTF-8"); |
|
|
|
httpPost.setEntity(entity); |
|
|
|
} |
|
|
|
|
|
|
|
// 执行请求 |
|
|
|
response = httpClient.execute(httpPost); |
|
|
|
|
|
|
|
// 检查响应状态 |
|
|
|
int statusCode = response.getStatusLine().getStatusCode(); |
|
|
|
if (statusCode == HttpStatus.SC_OK) { |
|
|
|
String result = EntityUtils.toString(response.getEntity(), "UTF-8"); |
|
|
|
log.info("微信API POST请求成功: {}", url); |
|
|
|
return result; |
|
|
|
} else { |
|
|
|
log.warn("微信API POST返回非200状态码: {}, URL: {}", statusCode, url); |
|
|
|
throw new RuntimeException("HTTP状态码异常: " + statusCode); |
|
|
|
} |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
log.error("微信API POST请求失败: {}, 错误: {}, 重试次数: {}", url, e.getMessage(), retryCount); |
|
|
|
|
|
|
|
// 如果还有重试机会,进行重试 |
|
|
|
if (retryCount < MAX_RETRY_COUNT) { |
|
|
|
log.info("准备进行第{}次重试...", retryCount + 1); |
|
|
|
try { |
|
|
|
Thread.sleep(1000 * (retryCount + 1)); // 递增延迟 |
|
|
|
} catch (InterruptedException ie) { |
|
|
|
Thread.currentThread().interrupt(); |
|
|
|
} |
|
|
|
return doPostWithRetry(url, jsonBody, retryCount + 1); |
|
|
|
} |
|
|
|
|
|
|
|
// 重试次数用尽,抛出异常 |
|
|
|
throw new RuntimeException("微信API POST请求失败,已重试" + MAX_RETRY_COUNT + "次: " + e.getMessage(), e); |
|
|
|
|
|
|
|
} finally { |
|
|
|
// 关闭资源 |
|
|
|
if (response != null) { |
|
|
|
try { |
|
|
|
response.close(); |
|
|
|
} catch (IOException e) { |
|
|
|
log.error("关闭响应失败: {}", e.getMessage()); |
|
|
|
} |
|
|
|
} |
|
|
|
if (httpClient != null) { |
|
|
|
try { |
|
|
|
httpClient.close(); |
|
|
|
} catch (IOException e) { |
|
|
|
log.error("关闭客户端失败: {}", e.getMessage()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |