具有已定义超时的 Java HTTP 客户端请求

Posted

技术标签:

【中文标题】具有已定义超时的 Java HTTP 客户端请求【英文标题】:Java HTTP Client Request with defined timeout 【发布时间】:2011-03-01 07:44:59 【问题描述】:

我想将 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 功能? 感谢您的评论。我已经更新了我的帖子。 【参考方案1】:

如果您使用的是 Http Client 4.3 及更高版本,您应该使用这个:

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

【讨论】:

谢谢!在找到答案之前,我至少花了 20 分钟试图弄清楚如何摆脱已弃用的命令来执行此操作。 忘记了SocketTimeout。此外,“默认”是否意味着所有 HttpClient 的默认值来自 create() 的 HttpClientBuilder 将通过 build() 方法提供?或者只是通过setDefaultRequestConfig(requestConfig) 的那些? 我说得有道理吗? @ADTC 你的问题有点令人困惑:)。默认请求配置将用于所有使用“仅”该 HttpClient 的 HttpPost、HttpGet、...实例。如果您创建了另一个 HttpClient 实例,则此请求配置将不会与该客户端一起使用。【参考方案2】:
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);

【讨论】:

这是做什么的?它设置了什么超时?请看***.com/questions/3000767/… Apache 的 HttpClient 有两个独立的超时时间:等待建立 TCP 连接多长时间的超时时间,以及等待后续数据字节多长时间的单独超时时间。 HttpConnectionParams.setConnectionTimeout() 是前者,HttpConnectionParams.setSoTimeout() 是后者。 什么是默认超时?是 0=无限吗? http.connection.timeout 整数 建立连接前的超时时间。零值表示不使用超时。 致未来的读者:应该注意的是,此处引用的类现在已弃用(截至 2016-07-05),尽管在 2010 年发布时这可能是一个很好的答案。请参阅此回答:***.com/a/19153314/192801 更新一些内容。【参考方案3】:

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

我建议在您的 HttpGet 或 HttpPost 实例上使用 RequestConfig:

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

【讨论】:

"使用上面的代码" 顺便说一句,简洁的答案。但是与迅雷的答案相比,将RequestConfig 设置为每个HttpPost 与将其设置为默认设置为HttpClient 有什么区别? 是的,你是对的,上面的代码指的是“接受的答案”,它不应该及时改变。无论如何我都会更新我的答案..【参考方案4】:

看起来你正在使用 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;

【讨论】:

这不会影响 Apache HTTP 客户端的超时时间。 HttpURLConnection 的超时概念是不够的。如果服务器开始响应,但随后挂起,则永远不会达到超时。 Apache 的 HttpClient 正是因为这个区别,所以是更好的选择。【参考方案5】:

Laz 最高的方法从 4.3 版本开始被弃用。因此,最好使用请求配置对象,然后构建 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 来设置等待来自连接管理器的连接的超时时间。

【讨论】:

【参考方案6】:

我发现在HttpConnectionParamsHttpConnectionManager 中设置超时设置并没有解决我们的问题。我们仅限使用org.apache.commons.httpclient 3.0.1 版。

我最终使用java.util.concurrent.ExecutorService 来监控HttpClient.executeMethod() 呼叫。

这是small, self-contained example

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

【讨论】:

【参考方案7】:

上面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

注意上面写的那一段

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

我希望这可以节省其他人我所经历的所有挠头。这将教会我不要彻底阅读文档!

【讨论】:

【参考方案8】:

Op 后来表示他们使用的是 Apache Commons HttpClient 3.0.1

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

【讨论】:

【参考方案9】:

HttpConnectionParams.setSoTimeout(params, 10*60*1000);// for 10 mins i have set the timeout

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

【讨论】:

以上是关于具有已定义超时的 Java HTTP 客户端请求的主要内容,如果未能解决你的问题,请参考以下文章

应该使用啥 http 状态代码来告诉客户端会话已超时?

接口测试整理1:HTTP状态码

HTTP协议状态码详解列表

java如何实现两个客服端之间互相发送信息

具有超时、最大大小和连接池的 http 请求

http status code