Apache Http 组件 - 如何使对代理的 CONNECT 请求超时?
Apache Http Components - How to timeout CONNECT request to a proxy?
不使用代理超时
我在本地启动netcat如下,基本上监听9090端口的连接:
netcat -l -p 9090
并使用 Apache HttpComponents,我创建了一个超时为 4 秒的连接..
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(4000)
.setConnectTimeout(4000)
.setConnectionRequestTimeout(4000)
.build();
HttpGet httpget = new HttpGet("http://127.0.0.1:9090");
httpget.setConfig(requestConfig);
try (CloseableHttpResponse response = HttpClients.createDefault().execute(httpget)) {}
在终端(我有 netcat
运行)我看到:
??]?D???;#???9?Mۡ?NR?w?{)?V?$?(=?&?*kj?
?5??98?#?'<?%?)g@? ?/??32?,?+?0??.?2???/??-?1???D
<!-- 4 seconds later -->
read(net): Connection reset by peer
在客户端我看到的是:
Exception in thread "main" org.apache.http.conn.ConnectTimeoutException:
Connect to 127.0.0.1:9090 [/127.0.0.1] failed: Read timed out
这一切都在意料之中。
使用代理超时
我根据文档 here.
稍微更改了客户端代码并配置了代理
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(4000)
.setConnectTimeout(4000)
.setConnectionRequestTimeout(4000)
.build();
HttpHost proxy = new HttpHost("127.0.0.1", 9090);
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
CloseableHttpClient httpclient = HttpClients.custom()
.setRoutePlanner(routePlanner)
.build();
HttpGet httpget = new HttpGet("https://127.0.0.1:9090");
httpget.setConfig(requestConfig);
try (CloseableHttpResponse response = httpclient.execute(httpget)) {}
然后再次启动 netcat,这次是在服务器端
CONNECT 127.0.0.1:9090 HTTP/1.1
Host: 127.0.0.1:9090
User-Agent: Apache-HttpClient/4.4.1 (Java/1.8.0_212)
但超时不适用于 CONNECT
。我只是永远等待..
如何将 httpclient
设置为超时 4 秒,就像我描述的第一种情况一样?
一种可能:
// This part is the same..
httpget.setConfig(requestConfig);
ExecutorService executorService = Executors.newSingleThreadExecutor();
Callable<CloseableHttpResponse> callable = () -> {
try (CloseableHttpResponse response = httpclient.execute(httpget)) {
return response;
}
};
Future<CloseableHttpResponse> future = executorService.submit(callable);
try {
future.get(4, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
httpget.abort();
executorService.shutdownNow();
}
但我愿意接受其他建议..
RequestConfig
只有在通过特定路由完全建立到目标的连接后才会生效。它们不适用于在主消息交换之前发生的 SSL 握手或任何 CONNECT 请求。
在 ConnectionManager
级别配置套接字超时以确保连接级别操作在一段时间不活动后超时。
不使用代理超时
我在本地启动netcat如下,基本上监听9090端口的连接:
netcat -l -p 9090
并使用 Apache HttpComponents,我创建了一个超时为 4 秒的连接..
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(4000)
.setConnectTimeout(4000)
.setConnectionRequestTimeout(4000)
.build();
HttpGet httpget = new HttpGet("http://127.0.0.1:9090");
httpget.setConfig(requestConfig);
try (CloseableHttpResponse response = HttpClients.createDefault().execute(httpget)) {}
在终端(我有 netcat
运行)我看到:
??]?D???;#???9?Mۡ?NR?w?{)?V?$?(=?&?*kj?
?5??98?#?'<?%?)g@? ?/??32?,?+?0??.?2???/??-?1???D
<!-- 4 seconds later -->
read(net): Connection reset by peer
在客户端我看到的是:
Exception in thread "main" org.apache.http.conn.ConnectTimeoutException:
Connect to 127.0.0.1:9090 [/127.0.0.1] failed: Read timed out
这一切都在意料之中。
使用代理超时
我根据文档 here.
稍微更改了客户端代码并配置了代理RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(4000)
.setConnectTimeout(4000)
.setConnectionRequestTimeout(4000)
.build();
HttpHost proxy = new HttpHost("127.0.0.1", 9090);
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
CloseableHttpClient httpclient = HttpClients.custom()
.setRoutePlanner(routePlanner)
.build();
HttpGet httpget = new HttpGet("https://127.0.0.1:9090");
httpget.setConfig(requestConfig);
try (CloseableHttpResponse response = httpclient.execute(httpget)) {}
然后再次启动 netcat,这次是在服务器端
CONNECT 127.0.0.1:9090 HTTP/1.1
Host: 127.0.0.1:9090
User-Agent: Apache-HttpClient/4.4.1 (Java/1.8.0_212)
但超时不适用于 CONNECT
。我只是永远等待..
如何将 httpclient
设置为超时 4 秒,就像我描述的第一种情况一样?
一种可能:
// This part is the same..
httpget.setConfig(requestConfig);
ExecutorService executorService = Executors.newSingleThreadExecutor();
Callable<CloseableHttpResponse> callable = () -> {
try (CloseableHttpResponse response = httpclient.execute(httpget)) {
return response;
}
};
Future<CloseableHttpResponse> future = executorService.submit(callable);
try {
future.get(4, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
httpget.abort();
executorService.shutdownNow();
}
但我愿意接受其他建议..
RequestConfig
只有在通过特定路由完全建立到目标的连接后才会生效。它们不适用于在主消息交换之前发生的 SSL 握手或任何 CONNECT 请求。
在 ConnectionManager
级别配置套接字超时以确保连接级别操作在一段时间不活动后超时。