Время ожидания Apache HttpClient
Есть ли способ указать тайм-аут для всего выполнения 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 секунд, независимо от ответа хоста.
Ответы
Ответ 1
В настоящее время нет способа установить максимальную продолжительность запроса такого типа: в основном вы хотите сказать Мне все равно, не истекает ли какой-либо конкретный период запроса, но весь запрос не должен длиться дольше, чем 15 секунд (например).
Лучше всего было бы запустить отдельный таймер, и когда он истечет, выберите менеджер подключений, используемый экземпляром HttpClient, и отключите соединение, которое должно прекратить связь. Сообщите мне, если это сработает для вас.
Ответ 2
Для более новой версии httpclient (например, http-компонентов 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);
Ответ 3
Прекрасно работает, как предложил Феми. Спасибо!
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
if(getMethod != null) {
getMethod.abort();
}
}
}, timeout * 1000);
Ответ 4
Изменив другие ответы, я решил использовать 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;
}
}
Ответ 5
В версии 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);
Ответ 6
Таймер это зло. Использование таймера или исполнителя или любого другого механизма, который создает поток/запускаемый объект для запроса, очень плохая идея. Несмотря на то, что вы нашли таймер с высоким рейтингом, пожалуйста, подумайте мудро и не делайте этого. В противном случае вы быстро столкнетесь с проблемами памяти в более или менее реальной среде. Решение, которое я предлагаю, потребует только 1 сторожевой поток и сэкономит вам ресурсы времени и нервов. В основном вы делаете 3 шага. 1. поместите запрос в кеш 2. удалите запрос из кеша после завершения 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());
}
public static void remove(HttpUriRequest request) {
cache.remove(request);
}
private static void cleanup() {
// find expired requests
List<HttpUriRequest> expired = cache.entrySet().stream()
.filter(e -> (System.currentTimeMillis() - e.getValue()) > expireInMillis)
.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);
}
}
}
Ответ 7
Это также работает:
HttpClient client = new DefaultHttpClient();
HttpConnectionParams.setConnectionTimeout(client.getParams(), timeout * 1000);
HttpConnectionParams.setSoTimeout(client.getParams(), timeout * 1000);