Java HTTP客户端请求和定义的超时时间

102

我想在我的云中对多台服务器进行BIT(内置测试)。 我需要在超时时间长的情况下请求失败。

我应该如何使用Java实现这个功能?

尝试类似下面的代码似乎不起作用。

public class TestNodeAliveness {
 public static NodeStatus nodeBIT(String elasticIP) throws ClientProtocolException, IOException {
  HttpClient client = new DefaultHttpClient();
  client.getParams().setIntParameter("http.connection.timeout", 1);

  HttpUriRequest request = new HttpGet("http://192.168.20.43");
  HttpResponse response = client.execute(request);

  System.out.println(response.toString());
  return null;
 }


 public static void main(String[] args) throws ClientProtocolException, IOException {
  nodeBIT("");
 }
}

-- 编辑:澄清正在使用的库 --

我正在使用来自Apache的httpclient库,这是相关的pom.xml部分:

 <dependency>
   <groupId>org.apache.httpcomponents</groupId>
   <artifactId>httpclient</artifactId>
   <version>4.0.1</version>
   <type>jar</type>
 </dependency>

你正在使用哪个库来提供所有HTTP功能? - nojo
9个回答

137

如果您使用的是Http Client 4.3及以上版本,则应使用以下内容:

RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30 * 1000).build();
HttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();

5
谢谢!在找到你的答案之前,我至少花了20分钟试图弄清楚如何摆脱这些不建议使用的命令来完成此操作。 - vextorspace
2
忘记了 SocketTimeout。还有,“default” 是指所有从 create() 方法创建的 HttpClientBuilder 通过 build() 方法提供的 HttpClient 都是默认值吗?还是只有那些通过 setDefaultRequestConfig(requestConfig) 的才是?我表达清楚了吗? - ADTC
@ADTC 你的问题有点令人困惑 :). 默认请求配置将用于所有使用“仅”该 HttpClient 的 HttpPost、HttpGet 等实例。如果您创建了另一个 HttpClient 实例,则此请求配置将不会与该客户端一起使用。 - Thunder

122
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

...

    // set the connection timeout value to 30 seconds (30000 milliseconds)
    final HttpParams httpParams = new BasicHttpParams();
    HttpConnectionParams.setConnectionTimeout(httpParams, 30000);
    client = new DefaultHttpClient(httpParams);

1
这是做什么的?它设置了什么超时时间?请访问https://dev59.com/Yk7Sa4cB1Zd3GeqP2U_v - Maxim Veksler
86
Apache的HttpClient有两个不同的超时时间:一个用于等待建立TCP连接的超时时间,另一个用于等待后续数据的字节的超时时间。HttpConnectionParams.setConnectionTimeout() 是前者,HttpConnectionParams.setSoTimeout() 是后者。 - benvolioT
7
默认超时时间是多少?是否为0代表无限制? - Tobia
1
http.connection.timeout 整型 连接建立的超时时间。零值表示不使用超时。 - maveroid
28
给未来读者:需要注意的是,此处提及的类已经停用(截至2016年7月5日),尽管在2010年发布时可能是一个好答案。有关更新一些的内容,请参见此回答:https://dev59.com/OXA75IYBdhLWcg3w-OZA#19153314。 - FrustratedWithFormsDesigner

41

在新的Apache HTTPClient库中,HttpParams已被弃用。使用Laz提供的代码会导致废弃警告。

我建议在您的HttpGet或HttpPost实例中改用RequestConfig。

final RequestConfig params = RequestConfig.custom().setConnectTimeout(3000).setSocketTimeout(3000).build();
httpPost.setConfig(params);

“使用上面的代码”<< Stack Overflow不是一个论坛,答案会因为多种因素而上下移动,所以我们不知道您指的是哪个代码。您能否说一些类似于“使用xyz答案中的代码”的话? - ADTC
4
顺便说一下,回答很不错。但与 Thunder 的答案相比,将 RequestConfig 设置为每个 HttpPost 的区别是什么,而不是将其默认设置为 HttpClient 中? - ADTC
2
是的,你说得对,上面的代码指的是“被接受的答案”,它不应该随时间而改变。无论如何,我还是会更新我的回答。 - pmartin8

11

看起来你正在使用HttpClient API,这是我所不了解的,但你可以使用Java核心代码编写类似的功能。

try {

   HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
   con.setRequestMethod("HEAD");
   con.setConnectTimeout(5000); //set timeout to 5 seconds
   return (con.getResponseCode() == HttpURLConnection.HTTP_OK);

} catch (java.net.SocketTimeoutException e) {
   return false;
} catch (java.io.IOException e) {
   return false;
}

2
这不会影响Apache HTTP客户端的超时时间。 - laz
5
HttpURLConnection 的超时概念不够充分。如果服务器开始响应,但之后卡住了,超时时间就永远不会到达。由于这种差异,Apache 的 HttpClient 是更好的选择。 - benvolioT

10

从版本4.3开始,Laz使用的最高up's方法已被弃用。因此最好使用Request Config对象,然后构建HTTP客户端。

    private CloseableHttpClient createHttpClient()
        {
        CloseableHttpClient httpClient;
        CommonHelperFunctions helperFunctions = new CommonHelperFunctions();
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(306);
        cm.setDefaultMaxPerRoute(108);
        RequestConfig requestConfig = RequestConfig.custom()
            .setConnectTimeout(15000)
            .setSocketTimeout(15000).build();
        httpClient = HttpClients.custom()
            .setConnectionManager(cm)
            .setDefaultRequestConfig(requestConfig).build();
        return httpClient;
        }

PoolingHttpClientConnectionManager用于设置默认最大连接数和每个路由的最大连接数。我已将它们分别设置为306和108。默认值对大多数情况不足以满足需求。

设置超时时间:我使用了RequestConfig对象。您还可以设置Connection Request Timeout属性,以设置等待来自连接管理器的连接的超时时间。


7
我发现在HttpConnectionParamsHttpConnectionManager中设置超时时间并不能解决我们的问题。我们只能使用版本为3.0.1的org.apache.commons.httpclient
最终我使用了一个java.util.concurrent.ExecutorService来监控HttpClient.executeMethod()方法的调用。
这里有一个简短、自包含的例子
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author Jeff Kirby
 * @since <pre>Jun 17, 2011</pre>
 */
public class Example {

   private static final String SITE = "http://some.website.com/upload";
   private static final int TIME_OUT_SECS = 5;

   // upload a file and return the response as a string
   public String post(File file) throws IOException, InterruptedException {
      final Part[] multiPart = { new FilePart("file", file.getName(), file) };
      final EntityEnclosingMethod post = new PostMethod(SITE);
      post.setRequestEntity(new MultipartRequestEntity(multiPart, post.getParams()));
      final ExecutorService executor = Executors.newSingleThreadExecutor();
      final List<Future<Integer>> futures = executor.invokeAll(Arrays.asList(new KillableHttpClient(post)), TIME_OUT_SECS, TimeUnit.SECONDS);
      executor.shutdown();
      if(futures.get(0).isCancelled()) {
         throw new IOException(SITE + " has timed out. It has taken more than " + TIME_OUT_SECS + " seconds to respond");
      }
      return post.getResponseBodyAsString();
   }

   private static class KillableHttpClient implements Callable<Integer> {

      private final EntityEnclosingMethod post;

      private KillableHttpClient(EntityEnclosingMethod post) {
         this.post = post;
      }

      public Integer call() throws Exception {
         return new HttpClient().executeMethod(post);
      }
   }
}

5
这在benvoliot的评论中已经提到过了。但是,我认为这值得成为一个顶级帖子,因为这确实让我感到困惑。如果它能帮助其他人,我就发出来了。
我编写了一个简单的测试客户端,CoreConnectionPNames.CONNECTION_TIMEOUT超时在那种情况下完美地工作。如果服务器没有响应,则请求将被取消。
然而,在服务器代码内部,相同的代码从未超时。
将其更改为在套接字连接活动(CoreConnectionPNames.SO_TIMEOUT)上超时,而不是在HTTP连接(CoreConnectionPNames.CONNECTION_TIMEOUT)上超时,解决了我的问题。
此外,请仔细阅读Apache文档:http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/org/apache/http/params/CoreConnectionPNames.html#CONNECTION_TIMEOUT 请注意其中的一段:

请注意,此参数仅适用于绑定到特定本地地址的连接。

我希望这能够帮助其他人避免像我一样费尽心思。这会教会我要认真阅读文档!

3

Op后来表示他们正在使用Apache Commons HttpClient 3.0.1。

 HttpClient client = new HttpClient();
        client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
        client.getHttpConnectionManager().getParams().setSoTimeout(5000);

1

HttpConnectionParams.setSoTimeout(params, 10*60*1000);//我设置了10分钟的超时时间

您也可以定义所需的超时时间。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接