package com.ruoyi.order.util.tencent.protocol;
|
|
import com.ruoyi.order.util.tencent.common.IWXPayDomain;
|
import com.ruoyi.order.util.tencent.common.WXPayConfig;
|
import com.ruoyi.order.util.tencent.common.WXPayUtil;
|
import org.apache.http.HttpEntity;
|
import org.apache.http.HttpResponse;
|
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.config.RequestConfig;
|
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.config.RegistryBuilder;
|
import org.apache.http.conn.ConnectTimeoutException;
|
import org.apache.http.conn.socket.ConnectionSocketFactory;
|
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
|
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
import org.apache.http.entity.StringEntity;
|
import org.apache.http.impl.client.HttpClientBuilder;
|
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
|
import org.apache.http.util.EntityUtils;
|
|
|
|
import javax.net.ssl.KeyManagerFactory;
|
import javax.net.ssl.SSLContext;
|
|
import java.io.InputStream;
|
import java.net.SocketTimeoutException;
|
import java.net.UnknownHostException;
|
import java.security.KeyStore;
|
import java.security.SecureRandom;
|
|
public class WXPayRequest {
|
private WXPayConfig config;
|
public WXPayRequest(WXPayConfig config) throws Exception{
|
|
this.config = config;
|
}
|
|
/**
|
* 请求,只请求一次,不做重试
|
* @param domain
|
* @param urlSuffix
|
* @param uuid
|
* @param data
|
* @param connectTimeoutMs
|
* @param readTimeoutMs
|
* @param useCert 是否使用证书,针对退款、撤销等操作
|
* @return
|
* @throws Exception
|
*/
|
private String requestOnce(final String domain, String urlSuffix, String uuid, String data, int connectTimeoutMs, int readTimeoutMs, boolean useCert) throws Exception {
|
BasicHttpClientConnectionManager connManager;
|
if (useCert) {
|
// 证书
|
char[] password = config.getMchID().toCharArray();
|
InputStream certStream = config.getCertStream();
|
KeyStore ks = KeyStore.getInstance("PKCS12");
|
ks.load(certStream, password);
|
|
// 实例化密钥库 & 初始化密钥工厂
|
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
kmf.init(ks, password);
|
|
// 创建 SSLContext
|
SSLContext sslContext = SSLContext.getInstance("TLS");
|
sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());
|
|
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
|
sslContext);
|
|
connManager = new BasicHttpClientConnectionManager(
|
RegistryBuilder.<ConnectionSocketFactory>create()
|
.register("http", PlainConnectionSocketFactory.getSocketFactory())
|
.register("https", sslConnectionSocketFactory)
|
.build(),
|
null,
|
null,
|
null
|
);
|
}
|
else {
|
connManager = new BasicHttpClientConnectionManager(
|
RegistryBuilder.<ConnectionSocketFactory>create()
|
.register("http", PlainConnectionSocketFactory.getSocketFactory())
|
.register("https", SSLConnectionSocketFactory.getSocketFactory())
|
.build(),
|
null,
|
null,
|
null
|
);
|
}
|
|
HttpClient httpClient = HttpClientBuilder.create()
|
.setConnectionManager(connManager)
|
.build();
|
|
String url = "https://" + domain + urlSuffix;
|
HttpPost httpPost = new HttpPost(url);
|
|
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(readTimeoutMs).setConnectTimeout(connectTimeoutMs).build();
|
httpPost.setConfig(requestConfig);
|
|
StringEntity postEntity = new StringEntity(data, "UTF-8");
|
httpPost.addHeader("Content-Type", "text/xml");
|
httpPost.addHeader("User-Agent", "wxpay sdk java v1.0 " + config.getMchID()); // TODO: 很重要,用来检测 sdk 的使用情况,要不要加上商户信息?
|
httpPost.setEntity(postEntity);
|
|
HttpResponse httpResponse = httpClient.execute(httpPost);
|
HttpEntity httpEntity = httpResponse.getEntity();
|
return EntityUtils.toString(httpEntity, "UTF-8");
|
|
}
|
|
|
private String request(String urlSuffix, String uuid, String data, int connectTimeoutMs, int readTimeoutMs, boolean useCert, boolean autoReport) throws Exception {
|
Exception exception = null;
|
long elapsedTimeMillis = 0;
|
long startTimestampMs = WXPayUtil.getCurrentTimestampMs();
|
boolean firstHasDnsErr = false;
|
boolean firstHasConnectTimeout = false;
|
boolean firstHasReadTimeout = false;
|
IWXPayDomain.DomainInfo domainInfo = config.getWXPayDomain().getDomain(config);
|
if(domainInfo == null){
|
throw new Exception("WXPayConfig.getWXPayDomain().getDomain() is empty or null");
|
}
|
try {
|
String result = requestOnce(domainInfo.domain, urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, useCert);
|
elapsedTimeMillis = WXPayUtil.getCurrentTimestampMs()-startTimestampMs;
|
config.getWXPayDomain().report(domainInfo.domain, elapsedTimeMillis, null);
|
WXPayReport.getInstance(config).report(
|
uuid,
|
elapsedTimeMillis,
|
domainInfo.domain,
|
domainInfo.primaryDomain,
|
connectTimeoutMs,
|
readTimeoutMs,
|
firstHasDnsErr,
|
firstHasConnectTimeout,
|
firstHasReadTimeout);
|
return result;
|
}
|
catch (UnknownHostException ex) { // dns 解析错误,或域名不存在
|
exception = ex;
|
firstHasDnsErr = true;
|
elapsedTimeMillis = WXPayUtil.getCurrentTimestampMs()-startTimestampMs;
|
WXPayUtil.getLogger().warn("UnknownHostException for domainInfo {}", domainInfo);
|
WXPayReport.getInstance(config).report(
|
uuid,
|
elapsedTimeMillis,
|
domainInfo.domain,
|
domainInfo.primaryDomain,
|
connectTimeoutMs,
|
readTimeoutMs,
|
firstHasDnsErr,
|
firstHasConnectTimeout,
|
firstHasReadTimeout
|
);
|
}
|
catch (ConnectTimeoutException ex) {
|
exception = ex;
|
firstHasConnectTimeout = true;
|
elapsedTimeMillis = WXPayUtil.getCurrentTimestampMs()-startTimestampMs;
|
WXPayUtil.getLogger().warn("connect timeout happened for domainInfo {}", domainInfo);
|
WXPayReport.getInstance(config).report(
|
uuid,
|
elapsedTimeMillis,
|
domainInfo.domain,
|
domainInfo.primaryDomain,
|
connectTimeoutMs,
|
readTimeoutMs,
|
firstHasDnsErr,
|
firstHasConnectTimeout,
|
firstHasReadTimeout
|
);
|
}
|
catch (SocketTimeoutException ex) {
|
exception = ex;
|
firstHasReadTimeout = true;
|
elapsedTimeMillis = WXPayUtil.getCurrentTimestampMs()-startTimestampMs;
|
WXPayUtil.getLogger().warn("timeout happened for domainInfo {}", domainInfo);
|
WXPayReport.getInstance(config).report(
|
uuid,
|
elapsedTimeMillis,
|
domainInfo.domain,
|
domainInfo.primaryDomain,
|
connectTimeoutMs,
|
readTimeoutMs,
|
firstHasDnsErr,
|
firstHasConnectTimeout,
|
firstHasReadTimeout);
|
}
|
catch (Exception ex) {
|
exception = ex;
|
elapsedTimeMillis = WXPayUtil.getCurrentTimestampMs()-startTimestampMs;
|
WXPayReport.getInstance(config).report(
|
uuid,
|
elapsedTimeMillis,
|
domainInfo.domain,
|
domainInfo.primaryDomain,
|
connectTimeoutMs,
|
readTimeoutMs,
|
firstHasDnsErr,
|
firstHasConnectTimeout,
|
firstHasReadTimeout);
|
}
|
config.getWXPayDomain().report(domainInfo.domain, elapsedTimeMillis, exception);
|
throw exception;
|
}
|
|
|
/**
|
* 可重试的,非双向认证的请求
|
* @param urlSuffix
|
* @param uuid
|
* @param data
|
* @return
|
*/
|
public String requestWithoutCert(String urlSuffix, String uuid, String data, boolean autoReport) throws Exception {
|
return this.request(urlSuffix, uuid, data, config.getHttpConnectTimeoutMs(), config.getHttpReadTimeoutMs(), false, autoReport);
|
//return requestWithoutCert(urlSuffix, uuid, data, config.getHttpConnectTimeoutMs(), config.getHttpReadTimeoutMs(), autoReport);
|
}
|
|
/**
|
* 可重试的,非双向认证的请求
|
* @param urlSuffix
|
* @param uuid
|
* @param data
|
* @param connectTimeoutMs
|
* @param readTimeoutMs
|
* @return
|
*/
|
public String requestWithoutCert(String urlSuffix, String uuid, String data, int connectTimeoutMs, int readTimeoutMs, boolean autoReport) throws Exception {
|
return this.request(urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, false, autoReport);
|
|
/*
|
String result;
|
Exception exception;
|
boolean shouldRetry = false;
|
|
boolean useCert = false;
|
try {
|
result = requestOnce(domain, urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, useCert);
|
return result;
|
}
|
catch (UnknownHostException ex) { // dns 解析错误,或域名不存在
|
exception = ex;
|
WXPayUtil.getLogger().warn("UnknownHostException for domain {}, try to use {}", domain, this.primaryDomain);
|
shouldRetry = true;
|
}
|
catch (ConnectTimeoutException ex) {
|
exception = ex;
|
WXPayUtil.getLogger().warn("connect timeout happened for domain {}, try to use {}", domain, this.primaryDomain);
|
shouldRetry = true;
|
}
|
catch (SocketTimeoutException ex) {
|
exception = ex;
|
shouldRetry = false;
|
}
|
catch (Exception ex) {
|
exception = ex;
|
shouldRetry = false;
|
}
|
|
if (shouldRetry) {
|
result = requestOnce(this.primaryDomain, urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, useCert);
|
return result;
|
}
|
else {
|
throw exception;
|
}
|
*/
|
}
|
|
/**
|
* 可重试的,双向认证的请求
|
* @param urlSuffix
|
* @param uuid
|
* @param data
|
* @return
|
*/
|
public String requestWithCert(String urlSuffix, String uuid, String data, boolean autoReport) throws Exception {
|
return this.request(urlSuffix, uuid, data, config.getHttpConnectTimeoutMs(), config.getHttpReadTimeoutMs(), true, autoReport);
|
//return requestWithCert(urlSuffix, uuid, data, config.getHttpConnectTimeoutMs(), config.getHttpReadTimeoutMs(), autoReport);
|
}
|
|
/**
|
* 可重试的,双向认证的请求
|
* @param urlSuffix
|
* @param uuid
|
* @param data
|
* @param connectTimeoutMs
|
* @param readTimeoutMs
|
* @return
|
*/
|
public String requestWithCert(String urlSuffix, String uuid, String data, int connectTimeoutMs, int readTimeoutMs, boolean autoReport) throws Exception {
|
return this.request(urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, true, autoReport);
|
|
/*
|
String result;
|
Exception exception;
|
boolean shouldRetry = false;
|
|
boolean useCert = true;
|
try {
|
result = requestOnce(domain, urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, useCert);
|
return result;
|
}
|
catch (ConnectTimeoutException ex) {
|
exception = ex;
|
WXPayUtil.getLogger().warn(String.format("connect timeout happened for domain {}, try to use {}", domain, this.primaryDomain));
|
shouldRetry = true;
|
}
|
catch (SocketTimeoutException ex) {
|
exception = ex;
|
shouldRetry = false;
|
}
|
catch (Exception ex) {
|
exception = ex;
|
shouldRetry = false;
|
}
|
|
if (shouldRetry && this.primaryDomain != null) {
|
result = requestOnce(this.primaryDomain, urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, useCert, autoReport);
|
return result;
|
}
|
else {
|
throw exception;
|
}
|
*/
|
}
|
}
|