使用Apache HttpClient如何设置请求和响应的超时

2022-09-01 02:49:01

我需要为我们对服务(而不是Web服务)发出的Http请求设置超时。我们正在使用Apache HTTP Client。我添加了这两行代码来设置请求超时和对服务的响应。

HttpConnectionParams.setConnectionTimeout(params, 10000);
HttpConnectionParams.setSoTimeout(params, 10000);

1)目前我已经将10秒设置为超时,因为我几乎立即看到来自服务的响应。我应该增加还是减少时间?

2)当响应超过10秒时会发生什么?它会引发异常吗?它会是什么异常?我还需要添加什么来在下面的代码中设置超时。

public HashMap<String, Object> getJSONData(String url) throw Exception{
    DefaultHttpClient httpClient = new DefaultHttpClient();
    HttpParams params = httpClient.getParams();
    HttpConnectionParams.setConnectionTimeout(params, 10000);
    HttpConnectionParams.setSoTimeout(params, 10000);
    HttpHost proxy = new HttpHost(getProxy(), getProxyPort());
    ConnRouteParams.setDefaultProxy(params, proxy);
    URI uri;
    InputStream data = null;
    try {
        uri = new URI(url);
        HttpGet method = new HttpGet(uri);
        HttpResponse response = httpClient.execute(method);
        data = response.getEntity().getContent();
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    Reader r = new InputStreamReader(data);
    HashMap<String, Object> jsonObj = (HashMap<String, Object>) GenericJSONUtil.fromJson(r);
    return jsonObj;
}

答案 1

我猜很多人来这里是因为标题和API被弃用了。HttpConnectionParams

使用最新版本的 Apache HTTP 客户端,您可以使用请求参数设置这些超时:

HttpPost request = new HttpPost(url);

RequestConfig requestConfig = RequestConfig.custom()
  .setSocketTimeout(TIMEOUT_MILLIS)
  .setConnectTimeout(TIMEOUT_MILLIS)
  .setConnectionRequestTimeout(TIMEOUT_MILLIS)
  .build();

request.setConfig(requestConfig);

或者,您也可以在创建 HTTP 客户端时使用 HTTP 客户端的生成器 API 来设置此设置,但还需要使用自定义套接字配置构建自定义连接管理器。

配置示例文件是了解如何配置 Apache HTTP 客户端的绝佳资源。


答案 2

您将看到的异常将是 和 。您使用的实际超时值应该是应用程序愿意等待的最长时间。关于读取超时的一个重要注意事项是,它对应于套接字读取上的超时。因此,这不是允许完整响应到达的时间,而是为单个套接字读取提供的时间。因此,如果有 4 个套接字读取,每个读取需要 9 秒,则总读取时间为 9 * 4 = 36 秒。ConnectTimeoutExceptionSocketTimeoutException

如果要指定响应到达的总时间(包括连接和总读取时间),可以将调用包装在线程中,并为此使用线程超时。例如,我通常做这样的事情:

Future<T> future = null;
future = pool.submit(new Callable<T>() {
    public T call() {
        return executeImpl(url);
    }   
}); 

try {
    return future.get(10, TimeUnit.SECONDS);
}   
catch (InterruptedException e) {
    log.warn("task interrupted", name);
}   
catch (ExecutionException e) {
    log.error(name + " execution exception", e); 
}   
catch (TimeoutException e) {
    log.debug("future timed out", name);
}

在上面的代码中所做的一些假设是:1)这是在具有url参数的函数中,2)它在具有名称变量的类中,3)日志是log4j实例,4)pool是一些线程池执行器。请注意,即使使用线程超时,也应在 HttpClient 上指定连接和套接字超时,以便慢速请求不会占用线程池中的资源。另请注意,我使用线程池,因为通常我在 Web 服务中使用它,因此线程池在一堆 tomcat 线程之间共享。您的环境可能不同,您可能更喜欢为每个调用生成一个新线程。

另外,我通常看到通过参数的成员函数设置的超时,如下所示:

params.setConnectionTimeout(10000);
params.setSoTimeout(10000);

但也许你的语法也有效(不确定)。


推荐