diff --git a/src/main/java/com/aliyun/tea/okhttp/ClientHelper.java b/src/main/java/com/aliyun/tea/okhttp/ClientHelper.java index 59d6ee9..e633cb1 100644 --- a/src/main/java/com/aliyun/tea/okhttp/ClientHelper.java +++ b/src/main/java/com/aliyun/tea/okhttp/ClientHelper.java @@ -20,7 +20,7 @@ public static OkHttpClient getOkHttpClient(String host, int port, Map map) { OkHttpClientBuilder builder = new OkHttpClientBuilder(); - builder = builder.protocols(map).connectTimeout(map).readTimeout(map).connectionPool(map).certificate(map).proxy(map).proxyAuthenticator(map); + builder = builder.protocols(map).connectTimeout(map).readTimeout(map).callTimeout(map).connectionPool(map).certificate(map).proxy(map).proxyAuthenticator(map); return builder.buildOkHttpClient(); } @@ -39,6 +39,9 @@ private static String getClientKey(String host, int port, Map ma (map.containsKey("socks5Proxy") && null != map.get("socks5Proxy") ? ":" + map.get("socks5Proxy") : "") + (map.containsKey("connectTimeout") && null != map.get("connectTimeout") ? ":" + map.get("connectTimeout") : "") + (map.containsKey("readTimeout") && null != map.get("readTimeout") ? ":" + map.get("readTimeout") : "") + + (map.containsKey("callTimeout") && null != map.get("callTimeout") ? ":" + map.get("callTimeout") : "") + + (map.containsKey("keepAliveDuration") && null != map.get("keepAliveDuration") ? ":" + map.get("keepAliveDuration") : "") + + (map.containsKey("maxIdleConns") && null != map.get("maxIdleConns") ? ":" + map.get("maxIdleConns") : "") + (map.containsKey("ignoreSSL") && null != map.get("ignoreSSL") ? ":" + map.get("ignoreSSL") : ""); } } diff --git a/src/main/java/com/aliyun/tea/okhttp/OkHttpClientBuilder.java b/src/main/java/com/aliyun/tea/okhttp/OkHttpClientBuilder.java index 22fcf02..130e069 100644 --- a/src/main/java/com/aliyun/tea/okhttp/OkHttpClientBuilder.java +++ b/src/main/java/com/aliyun/tea/okhttp/OkHttpClientBuilder.java @@ -71,6 +71,14 @@ public OkHttpClientBuilder readTimeout(Map map) { return this; } + public OkHttpClientBuilder callTimeout(Map map) { + if (map.containsKey("callTimeout") && null != map.get("callTimeout")) { + long callTimeout = Long.parseLong(String.valueOf(map.get("callTimeout"))); + this.builder.callTimeout(callTimeout, TimeUnit.MILLISECONDS); + } + return this; + } + public OkHttpClientBuilder connectionPool(Map map) { Object maxIdleConns = map.get("maxIdleConns"); int maxIdleConnections; diff --git a/src/test/java/com/aliyun/tea/okhttp/ClientHelperTest.java b/src/test/java/com/aliyun/tea/okhttp/ClientHelperTest.java index dfe0209..85e981b 100644 --- a/src/test/java/com/aliyun/tea/okhttp/ClientHelperTest.java +++ b/src/test/java/com/aliyun/tea/okhttp/ClientHelperTest.java @@ -45,6 +45,16 @@ public void getClientKeyTest() throws NoSuchMethodException, InvocationTargetExc map.put("ignoreSSL", false); str = (String) getClientKey.invoke(ClientHelper.class, "0:0:0:0:0:0:0:1", 0, map); Assert.assertEquals("0:0:0:0:0:0:0:1:0:http://127.0.0.1:80:https://127.0.0.1:80:socks5://user:password@127.0.0.1:1080:1000:2000:false", str); + + // callTimeout 应参与组装 client 缓存 key,位于 readTimeout 之后、ignoreSSL 之前 + map.put("callTimeout", 3000); + str = (String) getClientKey.invoke(ClientHelper.class, "0:0:0:0:0:0:0:1", 0, map); + Assert.assertEquals("0:0:0:0:0:0:0:1:0:http://127.0.0.1:80:https://127.0.0.1:80:socks5://user:password@127.0.0.1:1080:1000:2000:3000:false", str); + + // callTimeout 为 null 时不参与 key 组装 + map.put("callTimeout", null); + str = (String) getClientKey.invoke(ClientHelper.class, "0:0:0:0:0:0:0:1", 0, map); + Assert.assertEquals("0:0:0:0:0:0:0:1:0:http://127.0.0.1:80:https://127.0.0.1:80:socks5://user:password@127.0.0.1:1080:1000:2000:false", str); } @Test diff --git a/src/test/java/com/aliyun/tea/okhttp/OkHttpClientBuilderTest.java b/src/test/java/com/aliyun/tea/okhttp/OkHttpClientBuilderTest.java index 4bff8f5..f25afb7 100644 --- a/src/test/java/com/aliyun/tea/okhttp/OkHttpClientBuilderTest.java +++ b/src/test/java/com/aliyun/tea/okhttp/OkHttpClientBuilderTest.java @@ -32,6 +32,51 @@ public void timeOutTest() { Assert.assertEquals(888, client.readTimeoutMillis()); } + @Test + public void callTimeoutTest() { + // 未设置 callTimeout 时,默认应为 0(不限制),且不影响 readTimeout 默认值 + map.clear(); + OkHttpClientBuilder clientBuilder = new OkHttpClientBuilder(); + OkHttpClient client = clientBuilder.callTimeout(map).buildOkHttpClient(); + Assert.assertEquals(0, client.callTimeoutMillis()); + Assert.assertEquals(10000, client.readTimeoutMillis()); + + // 显式设置 callTimeout,应只作用于 callTimeout,readTimeout 保持默认 + map.clear(); + clientBuilder = new OkHttpClientBuilder(); + map.put("callTimeout", 1500); + client = clientBuilder.callTimeout(map).buildOkHttpClient(); + Assert.assertEquals(1500, client.callTimeoutMillis()); + Assert.assertEquals(10000, client.readTimeoutMillis()); + + // callTimeout 为 null 时按未设置处理,默认为 0 + map.clear(); + clientBuilder = new OkHttpClientBuilder(); + map.put("callTimeout", null); + client = clientBuilder.callTimeout(map).buildOkHttpClient(); + Assert.assertEquals(0, client.callTimeoutMillis()); + + // callTimeout 与 readTimeout 互不干扰,分别独立生效 + map.clear(); + clientBuilder = new OkHttpClientBuilder(); + map.put("callTimeout", 2000); + map.put("readTimeout", 888); + client = clientBuilder.readTimeout(map).callTimeout(map).buildOkHttpClient(); + Assert.assertEquals(2000, client.callTimeoutMillis()); + Assert.assertEquals(888, client.readTimeoutMillis()); + + // callTimeout 为非法字符串时抛出 NumberFormatException + map.clear(); + final OkHttpClientBuilder badBuilder = new OkHttpClientBuilder(); + map.put("callTimeout", "str"); + try { + badBuilder.callTimeout(map); + Assert.fail(); + } catch (NumberFormatException e) { + Assert.assertTrue(e.getMessage().contains("For input string: \"str\"")); + } + } + @Test public void connectionPoolTest() { map.clear();