diff --git a/pom.xml b/pom.xml
index d7924adb9d..4147bdcb86 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,7 +17,7 @@
com.squareup.okhttp3
okhttp
- 3.12.13
+ 4.12.0
com.google.code.gson
@@ -27,13 +27,18 @@
com.squareup.okhttp3
logging-interceptor
- 3.12.13
+ 4.12.0
org.apache.commons
commons-configuration2
2.12.0
+
+ javax.xml.bind
+ jaxb-api
+ 2.3.0
+
junit
junit
@@ -63,8 +68,8 @@
maven-compiler-plugin
2.3.2
- 1.7
- 1.7
+ 1.8
+ 1.8
UTF-8
diff --git a/src/main/java/com/tencentcloudapi/common/AbstractClient.java b/src/main/java/com/tencentcloudapi/common/AbstractClient.java
index 6efabaceb0..6531e70ee9 100644
--- a/src/main/java/com/tencentcloudapi/common/AbstractClient.java
+++ b/src/main/java/com/tencentcloudapi/common/AbstractClient.java
@@ -32,6 +32,8 @@
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -43,6 +45,7 @@
import java.net.Proxy;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
+import java.security.KeyStore;
import java.security.SecureRandom;
import java.sql.Date;
import java.text.SimpleDateFormat;
@@ -420,11 +423,25 @@ private void trySetSSLSocketFactory(HttpConnection conn) {
SSLSocketFactory sslSocketFactory = this.profile.getHttpProfile().getSslSocketFactory();
X509TrustManager trustManager = this.profile.getHttpProfile().getX509TrustManager();
if (sslSocketFactory != null) {
- if (trustManager != null) {
- this.httpConnection.setSSLSocketFactory(sslSocketFactory, trustManager);
- } else {
- this.httpConnection.setSSLSocketFactory(sslSocketFactory);
+ if (trustManager == null) {
+ // okhttp 4.x requires an explicit X509TrustManager alongside SSLSocketFactory.
+ // Fall back to the JVM default TrustManager so existing callers that only set
+ // SSLSocketFactory continue to work without requiring API changes.
+ try {
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(
+ TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init((KeyStore) null);
+ for (TrustManager tm : tmf.getTrustManagers()) {
+ if (tm instanceof X509TrustManager) {
+ trustManager = (X509TrustManager) tm;
+ break;
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to obtain default X509TrustManager for okhttp", e);
+ }
}
+ this.httpConnection.setSSLSocketFactory(sslSocketFactory, trustManager);
}
}
diff --git a/src/main/java/com/tencentcloudapi/common/http/HttpConnection.java b/src/main/java/com/tencentcloudapi/common/http/HttpConnection.java
index f837274e79..81bb6a68b4 100644
--- a/src/main/java/com/tencentcloudapi/common/http/HttpConnection.java
+++ b/src/main/java/com/tencentcloudapi/common/http/HttpConnection.java
@@ -56,11 +56,6 @@ public void setProxyAuthenticator(Authenticator authenticator) {
this.client = this.client.newBuilder().proxyAuthenticator(authenticator).build();
}
- @Deprecated
- public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory) {
- this.client = this.client.newBuilder().sslSocketFactory(sslSocketFactory).build();
- }
-
public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager) {
this.client = this.client.newBuilder().sslSocketFactory(sslSocketFactory, trustManager).build();
}
@@ -99,7 +94,7 @@ public Response postRequest(String url, String body) throws TencentCloudSDKExcep
MediaType contentType = MediaType.parse("application/x-www-form-urlencoded");
Request request = null;
try {
- request = new Request.Builder().url(url).post(RequestBody.create(contentType, body)).build();
+ request = new Request.Builder().url(url).post(RequestBody.create(body, contentType)).build();
} catch (IllegalArgumentException e) {
throw new TencentCloudSDKException(e.getClass().getName() + "-" + e.getMessage());
}
@@ -115,7 +110,7 @@ public Response postRequest(String url, String body, Headers headers)
request =
new Request.Builder()
.url(url)
- .post(RequestBody.create(contentType, body))
+ .post(RequestBody.create(body, contentType))
.headers(headers)
.build();
} catch (IllegalArgumentException e) {
@@ -133,7 +128,7 @@ public Response postRequest(String url, byte[] body, Headers headers)
request =
new Request.Builder()
.url(url)
- .post(RequestBody.create(contentType, body))
+ .post(RequestBody.create(body, contentType))
.headers(headers)
.build();
} catch (IllegalArgumentException e) {
diff --git a/src/test/java/com/tencentcloudapi/integration/commonclient/OkhttpUpgradeTest.java b/src/test/java/com/tencentcloudapi/integration/commonclient/OkhttpUpgradeTest.java
new file mode 100644
index 0000000000..c310a8850e
--- /dev/null
+++ b/src/test/java/com/tencentcloudapi/integration/commonclient/OkhttpUpgradeTest.java
@@ -0,0 +1,161 @@
+package com.tencentcloudapi.integration.commonclient;
+
+import com.tencentcloudapi.common.CommonClient;
+import com.tencentcloudapi.common.Credential;
+import com.tencentcloudapi.common.exception.TencentCloudSDKException;
+import com.tencentcloudapi.common.profile.ClientProfile;
+import com.tencentcloudapi.common.profile.HttpProfile;
+import okhttp3.OkHttp;
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+
+/**
+ * 验证 okhttp 升级到 4.x 后核心功能正常
+ * 运行前请设置环境变量:
+ * TENCENTCLOUD_SECRET_ID
+ * TENCENTCLOUD_SECRET_KEY
+ */
+public class OkhttpUpgradeTest {
+
+ private Credential getCredential() {
+ return new Credential(
+ System.getenv("TENCENTCLOUD_SECRET_ID"),
+ System.getenv("TENCENTCLOUD_SECRET_KEY"));
+ }
+
+ /**
+ * 验证 okhttp 版本已升级到 4.x
+ */
+ @Test
+ public void testOkhttpVersion() {
+ String version = OkHttp.VERSION;
+ System.out.println("OkHttp version: " + version);
+ Assert.assertTrue("期望 okhttp 版本为 4.x,实际为: " + version,
+ version.startsWith("4."));
+ }
+
+ /**
+ * 基础 API 调用:DescribeInstances(验证 RequestBody.create 参数顺序修改后正常)
+ */
+ @Test
+ public void testBasicApiCall() {
+ Credential cred = getCredential();
+ CommonClient client = new CommonClient("cvm", "2017-03-12", cred, "ap-guangzhou");
+ try {
+ String resp = client.call("DescribeInstances",
+ "{\"Filters\":[{\"Name\":\"zone\",\"Values\":[\"ap-guangzhou-1\"]}]}");
+ System.out.println("DescribeInstances 响应: " + resp.substring(0, Math.min(200, resp.length())));
+ Assert.assertTrue("响应中应包含 RequestId", resp.contains("RequestId"));
+ } catch (TencentCloudSDKException e) {
+ Assert.fail("API 调用失败: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 验证 HTTPS 正常(默认 SSLSocketFactory,okhttp 4.x 默认连接)
+ */
+ @Test
+ public void testHttpsCall() {
+ Credential cred = getCredential();
+ HttpProfile httpProfile = new HttpProfile();
+ httpProfile.setProtocol("https://");
+ ClientProfile clientProfile = new ClientProfile();
+ clientProfile.setHttpProfile(httpProfile);
+
+ CommonClient client = new CommonClient("cvm", "2017-03-12", cred, "ap-guangzhou", clientProfile);
+ try {
+ String resp = client.call("DescribeInstances", "{}");
+ System.out.println("HTTPS 调用响应: " + resp.substring(0, Math.min(200, resp.length())));
+ Assert.assertTrue("HTTPS 调用应包含 RequestId", resp.contains("RequestId"));
+ } catch (TencentCloudSDKException e) {
+ Assert.fail("HTTPS 调用失败: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 验证仅设置 SSLSocketFactory(不传 TrustManager)时 okhttp 4.x 兼容性
+ * AbstractClient 改动:自动获取默认 X509TrustManager,避免报错
+ */
+ @Test
+ public void testSSLSocketFactoryOnlyCompat() throws NoSuchAlgorithmException, KeyManagementException {
+ Credential cred = getCredential();
+
+ // 只创建 SSLSocketFactory,不显式传 TrustManager(模拟旧调用方式)
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(null, null, null); // 使用 JVM 默认 TrustManager
+ SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+
+ HttpProfile httpProfile = new HttpProfile();
+ httpProfile.setSslSocketFactory(sslSocketFactory);
+ // 注意:不调用 setX509TrustManager,测试 AbstractClient 的自动兜底逻辑
+ ClientProfile clientProfile = new ClientProfile();
+ clientProfile.setHttpProfile(httpProfile);
+
+ CommonClient client = new CommonClient("cvm", "2017-03-12", cred, "ap-guangzhou", clientProfile);
+ try {
+ String resp = client.call("DescribeInstances", "{}");
+ System.out.println("SSLSocketFactory-only 调用响应: " + resp.substring(0, Math.min(200, resp.length())));
+ Assert.assertTrue("应包含 RequestId", resp.contains("RequestId"));
+ } catch (TencentCloudSDKException e) {
+ Assert.fail("SSLSocketFactory only 调用失败(兼容性回归): " + e.getMessage());
+ }
+ }
+
+ /**
+ * 验证自定义 SSLSocketFactory + TrustManager(信任所有证书)调用正常
+ */
+ @Test
+ public void testCustomSSLSocketFactory() throws Exception {
+ Credential cred = getCredential();
+
+ TrustManager[] trustAllCerts = new TrustManager[]{
+ new X509TrustManager() {
+ public void checkClientTrusted(X509Certificate[] chain, String authType) {}
+ public void checkServerTrusted(X509Certificate[] chain, String authType) {}
+ public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
+ }
+ };
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
+ SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+
+ HttpProfile httpProfile = new HttpProfile();
+ httpProfile.setSslSocketFactory(sslSocketFactory);
+ httpProfile.setX509TrustManager((X509TrustManager) trustAllCerts[0]);
+ ClientProfile clientProfile = new ClientProfile();
+ clientProfile.setHttpProfile(httpProfile);
+
+ CommonClient client = new CommonClient("cvm", "2017-03-12", cred, "ap-guangzhou", clientProfile);
+ try {
+ String resp = client.call("DescribeInstances", "{}");
+ System.out.println("自定义 SSL 调用响应: " + resp.substring(0, Math.min(200, resp.length())));
+ Assert.assertTrue("应包含 RequestId", resp.contains("RequestId"));
+ } catch (TencentCloudSDKException e) {
+ Assert.fail("自定义 SSL 调用失败: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 验证 POST JSON 请求(覆盖 RequestBody.create(body, contentType) 调用路径)
+ */
+ @Test
+ public void testPostJsonRequest() {
+ Credential cred = getCredential();
+ CommonClient client = new CommonClient("sts", "2018-08-13", cred, "ap-guangzhou");
+ try {
+ String resp = client.call("GetCallerIdentity", "{}");
+ System.out.println("GetCallerIdentity 响应: " + resp.substring(0, Math.min(200, resp.length())));
+ Assert.assertTrue("应包含 RequestId", resp.contains("RequestId"));
+ } catch (TencentCloudSDKException e) {
+ Assert.fail("POST JSON 请求失败: " + e.getMessage());
+ }
+ }
+}