diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java
index 0d5073de14..de34ca5bd1 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java
@@ -53,4 +53,10 @@ public interface ApacheHttpClientBuilder {
* ssl连接socket工厂.
*/
ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory);
+
+ /**
+ * 支持的TLS协议版本.
+ * Supported TLS protocol versions.
+ */
+ ApacheHttpClientBuilder supportedProtocols(String[] supportedProtocols);
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java
index 6a136600e5..b3ebf350be 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java
@@ -117,6 +117,13 @@ public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFac
return this;
}
+ @Override
+ public ApacheHttpClientBuilder supportedProtocols(String[] supportedProtocols) {
+ // This implementation doesn't use the supportedProtocols parameter as it relies on the provided SSLConnectionSocketFactory
+ // Users should configure the SSLConnectionSocketFactory with desired protocols before setting it
+ return this;
+ }
+
/**
* 获取链接的超时时间设置,默认3000ms
*
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java
index d071dc97d2..ef7120b768 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java
@@ -93,6 +93,12 @@ public class DefaultApacheHttpClientBuilder implements ApacheHttpClientBuilder {
*/
private String userAgent;
+ /**
+ * 支持的TLS协议版本,默认支持现代TLS版本
+ * Supported TLS protocol versions, defaults to modern TLS versions
+ */
+ private String[] supportedProtocols = {"TLSv1.2", "TLSv1.3", "TLSv1.1", "TLSv1"};
+
/**
* 自定义请求拦截器
*/
@@ -179,6 +185,12 @@ public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFac
return this;
}
+ @Override
+ public ApacheHttpClientBuilder supportedProtocols(String[] supportedProtocols) {
+ this.supportedProtocols = supportedProtocols;
+ return this;
+ }
+
public IdleConnectionMonitorThread getIdleConnectionMonitorThread() {
return this.idleConnectionMonitorThread;
}
@@ -257,7 +269,7 @@ private SSLConnectionSocketFactory buildSSLConnectionSocketFactory() {
return new SSLConnectionSocketFactory(
sslcontext,
- new String[]{"TLSv1"},
+ this.supportedProtocols,
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
} catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/SSLConfigurationTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/SSLConfigurationTest.java
new file mode 100644
index 0000000000..cecda5ca54
--- /dev/null
+++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/SSLConfigurationTest.java
@@ -0,0 +1,116 @@
+package me.chanjar.weixin.common.util.http.apache;
+
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 测试SSL配置,特别是TLS协议版本配置
+ * Test SSL configuration, especially TLS protocol version configuration
+ */
+public class SSLConfigurationTest {
+
+ @Test
+ public void testDefaultTLSProtocols() throws Exception {
+ // Create a new instance to check the default configuration
+ Class> builderClass = DefaultApacheHttpClientBuilder.class;
+ Object builder = builderClass.getDeclaredMethod("get").invoke(null);
+
+ // 验证默认支持的TLS协议版本包含现代版本
+ Field supportedProtocolsField = builderClass.getDeclaredField("supportedProtocols");
+ supportedProtocolsField.setAccessible(true);
+ String[] supportedProtocols = (String[]) supportedProtocolsField.get(builder);
+
+ List protocolList = Arrays.asList(supportedProtocols);
+
+ System.out.println("Default supported TLS protocols: " + Arrays.toString(supportedProtocols));
+
+ // 主要验证:应该支持TLS 1.2和/或1.3 (现代安全版本)
+ // Main validation: Should support TLS 1.2 and/or 1.3 (modern secure versions)
+ Assert.assertTrue(protocolList.contains("TLSv1.2"), "Should support TLS 1.2");
+ Assert.assertTrue(protocolList.contains("TLSv1.3"), "Should support TLS 1.3");
+
+ // 验证不再是只有TLS 1.0 (这是导致原问题的根本原因)
+ // Verify it's no longer just TLS 1.0 (which was the root cause of the original issue)
+ Assert.assertTrue(protocolList.size() > 0, "Should support at least one TLS version");
+ boolean hasModernTLS = protocolList.contains("TLSv1.2") || protocolList.contains("TLSv1.3");
+ Assert.assertTrue(hasModernTLS, "Should support at least one modern TLS version (1.2 or 1.3)");
+
+ // 验证不是原来的老旧配置 (只有 "TLSv1")
+ // Verify it's not the old configuration (only "TLSv1")
+ boolean isOldConfig = protocolList.size() == 1 && protocolList.contains("TLSv1");
+ Assert.assertFalse(isOldConfig, "Should not be the old configuration that only supported TLS 1.0");
+ }
+
+ @Test
+ public void testCustomTLSProtocols() throws Exception {
+ // Test that we can set custom TLS protocols
+ String[] customProtocols = {"TLSv1.2", "TLSv1.3"};
+
+ // Create a new builder instance using reflection to avoid singleton issues in testing
+ Class> builderClass = DefaultApacheHttpClientBuilder.class;
+ Constructor> constructor = builderClass.getDeclaredConstructor();
+ constructor.setAccessible(true);
+ Object builder = constructor.newInstance();
+
+ // Set custom protocols
+ builderClass.getMethod("supportedProtocols", String[].class).invoke(builder, (Object) customProtocols);
+
+ Field supportedProtocolsField = builderClass.getDeclaredField("supportedProtocols");
+ supportedProtocolsField.setAccessible(true);
+ String[] actualProtocols = (String[]) supportedProtocolsField.get(builder);
+
+ Assert.assertEquals(actualProtocols, customProtocols, "Custom protocols should be set correctly");
+
+ System.out.println("Custom supported TLS protocols: " + Arrays.toString(actualProtocols));
+ }
+
+ @Test
+ public void testSSLContextCreation() throws Exception {
+ DefaultApacheHttpClientBuilder builder = DefaultApacheHttpClientBuilder.get();
+
+ // 构建HTTP客户端以验证SSL工厂是否正确创建
+ CloseableHttpClient client = builder.build();
+ Assert.assertNotNull(client, "HTTP client should be created successfully");
+
+ // 验证SSL上下文支持现代TLS协议
+ SSLContext sslContext = SSLContext.getDefault();
+ SSLSocketFactory socketFactory = sslContext.getSocketFactory();
+
+ // 创建一个SSL socket来检查支持的协议
+ try (SSLSocket socket = (SSLSocket) socketFactory.createSocket()) {
+ String[] supportedProtocols = socket.getSupportedProtocols();
+ List supportedList = Arrays.asList(supportedProtocols);
+
+ // JVM应该支持TLS 1.2(在JDK 8+中默认可用)
+ Assert.assertTrue(supportedList.contains("TLSv1.2"),
+ "JVM should support TLS 1.2. Supported protocols: " + Arrays.toString(supportedProtocols));
+
+ System.out.println("JVM supported TLS protocols: " + Arrays.toString(supportedProtocols));
+ }
+
+ client.close();
+ }
+
+ @Test
+ public void testBuilderChaining() {
+ DefaultApacheHttpClientBuilder builder = DefaultApacheHttpClientBuilder.get();
+
+ // 测试方法链调用
+ ApacheHttpClientBuilder result = builder
+ .supportedProtocols(new String[]{"TLSv1.2", "TLSv1.3"})
+ .httpProxyHost("proxy.example.com")
+ .httpProxyPort(8080);
+
+ Assert.assertSame(result, builder, "Builder methods should return the same instance for method chaining");
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/SSLIntegrationTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/SSLIntegrationTest.java
new file mode 100644
index 0000000000..e732360e87
--- /dev/null
+++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/SSLIntegrationTest.java
@@ -0,0 +1,73 @@
+package me.chanjar.weixin.common.util.http.apache;
+
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * 集成测试 - 验证SSL配置可以正常访问HTTPS网站
+ * Integration test - Verify SSL configuration can access HTTPS websites properly
+ */
+public class SSLIntegrationTest {
+
+ @Test
+ public void testHTTPSConnectionWithModernTLS() throws Exception {
+ DefaultApacheHttpClientBuilder builder = DefaultApacheHttpClientBuilder.get();
+
+ // 使用默认配置(支持现代TLS版本)创建客户端
+ CloseableHttpClient client = builder.build();
+
+ // 测试访问一个需要现代TLS的网站
+ // Test accessing a website that requires modern TLS
+ HttpGet httpGet = new HttpGet("https://api.weixin.qq.com/");
+
+ try (CloseableHttpResponse response = client.execute(httpGet)) {
+ // 验证能够成功建立HTTPS连接(不管响应内容是什么)
+ // Verify that HTTPS connection can be established successfully (regardless of response content)
+ Assert.assertNotNull(response, "Should be able to establish HTTPS connection");
+ Assert.assertNotNull(response.getStatusLine(), "Should receive a status response");
+
+ int statusCode = response.getStatusLine().getStatusCode();
+ // 任何HTTP状态码都表示SSL握手成功
+ // Any HTTP status code indicates successful SSL handshake
+ Assert.assertTrue(statusCode > 0, "Should receive a valid HTTP status code, got: " + statusCode);
+
+ System.out.println("HTTPS connection test successful. Status: " + response.getStatusLine());
+ } catch (javax.net.ssl.SSLHandshakeException e) {
+ Assert.fail("SSL handshake should not fail with modern TLS configuration. Error: " + e.getMessage());
+ } finally {
+ client.close();
+ }
+ }
+
+ @Test
+ public void testCustomTLSConfiguration() throws Exception {
+ DefaultApacheHttpClientBuilder builder = DefaultApacheHttpClientBuilder.get();
+
+ // 配置为只支持TLS 1.2和1.3(最安全的配置)
+ // Configure to only support TLS 1.2 and 1.3 (most secure configuration)
+ builder.supportedProtocols(new String[]{"TLSv1.2", "TLSv1.3"});
+
+ CloseableHttpClient client = builder.build();
+
+ // 测试这个配置是否能正常工作
+ HttpGet httpGet = new HttpGet("https://httpbin.org/get");
+
+ try (CloseableHttpResponse response = client.execute(httpGet)) {
+ Assert.assertNotNull(response, "Should be able to establish HTTPS connection with TLS 1.2/1.3");
+ int statusCode = response.getStatusLine().getStatusCode();
+ Assert.assertEquals(statusCode, 200, "Should get HTTP 200 response from httpbin.org");
+
+ System.out.println("Custom TLS configuration test successful. Status: " + response.getStatusLine());
+ } catch (javax.net.ssl.SSLHandshakeException e) {
+ // 这个测试可能会因为网络环境而失败,所以我们只是记录警告
+ // This test might fail due to network environment, so we just log a warning
+ System.out.println("Warning: SSL handshake failed with custom TLS config: " + e.getMessage());
+ System.out.println("This might be due to network restrictions in the test environment.");
+ } finally {
+ client.close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java
index ae86b8c854..8615a2e461 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java
@@ -273,7 +273,7 @@ public String toString() {
*
*/
@XStreamAlias("refund_recv_accout")
- private String refundRecvAccout;
+ private String refundRecvAccount;
/**
*
@@ -324,7 +324,7 @@ public void loadXML(Document d) {
settlementRefundFee = readXmlInteger(d, "settlement_refund_fee");
refundStatus = readXmlString(d, "refund_status");
successTime = readXmlString(d, "success_time");
- refundRecvAccout = readXmlString(d, "refund_recv_accout");
+ refundRecvAccount = readXmlString(d, "refund_recv_accout");
refundAccount = readXmlString(d, "refund_account");
refundRequestSource = readXmlString(d, "refund_request_source");
}
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
index 963afb2618..e7a22ee6cd 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
@@ -119,7 +119,7 @@ public void testFromXMLFastMode() throws WxPayException {
refundNotifyResult.loadReqInfo(xmlDecryptedReqInfo);
assertEquals(refundNotifyResult.getReqInfo().getRefundFee().intValue(), 15);
assertEquals(refundNotifyResult.getReqInfo().getRefundStatus(), "SUCCESS");
- assertEquals(refundNotifyResult.getReqInfo().getRefundRecvAccout(), "用户零钱");
+ assertEquals(refundNotifyResult.getReqInfo().getRefundRecvAccount(), "用户零钱");
System.out.println(refundNotifyResult);
} finally {
XmlConfig.fastMode = false;