[英]Apache HttpClient timeout
有没有办法为HttpClient
的整个执行指定超时?
我尝试了以下方法:
httpClient.getParams().setParameter("http.socket.timeout", timeout * 1000);
httpClient.getParams().setParameter("http.connection.timeout", timeout * 1000);
httpClient.getParams().setParameter("http.connection-manager.timeout", new Long(timeout * 1000));
httpClient.getParams().setParameter("http.protocol.head-body-timeout", timeout * 1000);
它实际上工作正常,除非远程主机发回数据——即使是一字节/秒——它将继续永远读取,但我想在最多 10 秒内中断连接。 主机是否响应。
For a newer version of httpclient (eg http components 4.3 - https://hc.apache.org/httpcomponents-client-4.3.x/index.html ):
int CONNECTION_TIMEOUT_MS = timeoutSeconds * 1000; // Timeout in millis.
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(CONNECTION_TIMEOUT_MS)
.setConnectTimeout(CONNECTION_TIMEOUT_MS)
.setSocketTimeout(CONNECTION_TIMEOUT_MS)
.build();
HttpPost httpPost = new HttpPost(URL);
httpPost.setConfig(requestConfig);
目前没有办法设置这种最大请求持续时间:基本上你想说我不在乎任何特定的请求阶段是否超时,但整个请求的持续时间不能超过 15 秒(例如) .
最好的办法是运行一个单独的计时器,当它到期时,获取 HttpClient 实例使用的连接管理器并关闭连接,这应该会终止链接。 让我知道这是否适合你。
按照 Femi 的建议,工作正常。 谢谢!
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
if(getMethod != null) {
getMethod.abort();
}
}
}, timeout * 1000);
计时器是邪恶的。 使用计时器或执行程序或任何其他机制为每个请求创建线程/可运行 object 是一个非常糟糕的主意。 请明智地思考,不要这样做。 否则,您将很快遇到或多或少真实环境的各种 memory 问题。 想象一下 1000 req/min 意味着 1000 个线程或工作线程/分钟。 可怜的GC。 我提出的解决方案只需要 1 个看门狗线程,可以节省您的资源时间和精力。 基本上你做3个步骤。
你的缓存和看门狗线程可能看起来像这样。
import org.apache.http.client.methods.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;
public class RequestCache {
private static final long expireInMillis = 300000;
private static final Map<HttpUriRequest, Long> cache = new ConcurrentHashMap<>();
private static final ScheduledExecutorService exe = Executors.newScheduledThreadPool(1);
static {
// run clean up every N minutes
exe.schedule(RequestCache::cleanup, 1, TimeUnit.MINUTES);
}
public static void put(HttpUriRequest request) {
cache.put(request, System.currentTimeMillis()+expireInMillis);
}
public static void remove(HttpUriRequest request) {
cache.remove(request);
}
private static void cleanup() {
long now = System.currentTimeMillis();
// find expired requests
List<HttpUriRequest> expired = cache.entrySet().stream()
.filter(e -> e.getValue() > now)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
// abort requests
expired.forEach(r -> {
if (!r.isAborted()) {
r.abort();
}
cache.remove(r);
});
}
}
以及以下 sudo 代码如何使用缓存
import org.apache.http.client.methods.*;
public class RequestSample {
public void processRequest() {
HttpUriRequest req = null;
try {
req = createRequest();
RequestCache.put(req);
execute(req);
} finally {
RequestCache.remove(req);
}
}
}
在其他答案的基础上,我的解决方案是使用HttpRequestInterceptor
为每个请求添加可运行的中止。 我也将Timer
换成了ScheduledExecutorService
。
public class TimeoutInterceptor implements HttpRequestInterceptor {
private int requestTimeout = 1 * DateTimeConstants.MILLIS_PER_MINUTE;
private ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
public TimeoutInterceptor() { }
public TimeoutInterceptor(final int requestTimeout) {
this.requestTimeout = requestTimeout;
}
@Override
public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
if (request instanceof AbstractExecutionAwareRequest) {
final AbstractExecutionAwareRequest abortableRequest = (AbstractExecutionAwareRequest) request;
setAbort(abortableRequest);
} else if (request instanceof HttpRequestWrapper) {
HttpRequestWrapper wrapper = (HttpRequestWrapper) request;
this.process(wrapper.getOriginal(), context);
}
}
/**
* @param abortableRequest
*/
private void setAbort(final AbstractExecutionAwareRequest abortableRequest) {
final SoftReference<AbstractExecutionAwareRequest> requestRef = new SoftReference<AbstractExecutionAwareRequest>(abortableRequest);
executorService.schedule(new Runnable() {
@Override
public void run() {
AbstractExecutionAwareRequest actual = requestRef.get();
if (actual != null && !actual.isAborted()) {
actual.abort();
}
}
}, requestTimeout, TimeUnit.MILLISECONDS);
}
public void setRequestTimeout(final int requestTimeout) {
this.requestTimeout = requestTimeout;
}
}
在 HttpClient 4.3 版本中,您可以使用以下示例.. 说 5 秒
int timeout = 5;
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(timeout * 1000)
.setConnectionRequestTimeout(timeout * 1000)
.setSocketTimeout(timeout * 1000).build();
CloseableHttpClient client =
HttpClientBuilder.create().setDefaultRequestConfig(config).build();
HttpGet request = new HttpGet("http://localhost:8080/service"); // GET Request
response = client.execute(request);
这也是工作:
HttpClient client = new DefaultHttpClient();
HttpConnectionParams.setConnectionTimeout(client.getParams(), timeout * 1000);
HttpConnectionParams.setSoTimeout(client.getParams(), timeout * 1000);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.