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);

它实际上工作得很好,除非远程主机发送回数据-即使是1字节/秒-它将永远继续读取!但是我想在最多10秒内中断连接,无论主机是否响应

新版本的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);

目前没有办法设置这种类型的最大请求持续时间:基本上你想说我不在乎任何特定的请求阶段是否超时,但整个请求不能持续超过15秒(例如)。

最好的办法是运行一个单独的计时器,当它过期时,获取HttpClient实例使用的连接管理器并关闭连接,这应该会终止链接。

工作正常,正如Femi所建议的那样。谢谢!

Timer timer = new Timer();
timer.schedule(new TimerTask() {
    public void run() {
        if(getMethod != null) {
            getMethod.abort();
        }
    }
}, timeout * 1000);

计时器是邪恶的!使用计时器或执行器或任何其他为每个请求创建线程/可运行对象的机制是一个非常糟糕的主意。请明智地考虑一下,不要这样做。否则,您将很快遇到各种内存问题或多或少的真实环境。想象一下,1000 req/min意味着1000个线程或worker/min。我提出的解决方案只需要一个看门狗线程,将节省您的资源,时间和神经。基本上你要做3个步骤。

    将请求放入缓存。当请求完成时从缓存中删除。
  1. 终止未在限制内完成的请求。

您的缓存和看门狗线程可能看起来像这样。

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向每个请求添加中止可运行程序。我也换出了TimerScheduledExecutorService

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);

相关内容

  • 没有找到相关文章

最新更新