HttpClient 超时设置

本文基于httpClient4.5版本

maven依赖

<dependency>
   <groupId>org.apache.httpcomponents</groupId>
   <artifactId>httpclient</artifactId>
   <version>4.5.3</version>
</dependency>

本文不详细展开对httpclient的详细讲解, 只展示具体用法

 

httpclient 4.5版本设置超时有三种

1connectTimeOut

建立连接超时时间, 众所周知 http的三次握手机智, 在正式进行数据传输之前需要先完成三次握手. connectTimeOut就是指在进行三次握手行为时所设置的超时. 例如在文末例子中,我访问了一个虚假的域名,http://74.125.203.100, 因为域名本身就不存在, 所以三次握手行为肯定是失败的, 所以链接肯定是无法建立的. 根据如下代码, 设置的时间是5000毫秒 所以运行程序会在五秒之后抛出链接超时异常

2socketTimeOut

建立链接成功数据传输导致的超时时间, 当三次握手行为成功后, 即可通过所建立的http通道进行数据传输, 此时如果超过设置时间并没有获取到对应的数据包就会抛出超时异常, 此处有个需要注意点是socketTimeOut所处理的超时时间是指相邻两个数据包传输之间所经历的时间. 例如链接建立成功后 由于数据过大 服务端每隔1秒传送一个数据包给客户端, 此时设置的超时时间为3秒,一共发送了10个数据包,总共耗时10秒, 请求总共花费10秒, 但是并不会报超时异常, 是因为每次数据包传输之间的时间都不超过3秒,所以不会抛出异常, 总结一下 socketTimeOut是指链接建立成功后,数据包传输之间时间超时限制.

3 connectionRequestTimeOut

从httpclient连接池获取连接超时限制 这个超时没有测试, 以后详细解释

时间单位是毫秒

.setConnectionRequestTimeout(1000) // 从数据库连接池获取连接超时时间设置

.setSocketTimeout(1000)   // socket连接建立成功, 数据传输响应超时

.setConnectTimeout(5000) // 建立socket链接超时时间

 

https访问超时无效问题

由于我在项目中既要访问http接口也要访问https接口,设置超时后发现https不起作用,经过排查跟https 对应的HttpClient对象有关,下面贴上新旧代码

初步排查是创建httpsClient时候导致的超时不生效(此时是https接口访问生效, https接口访问不生效), 目前尚未发现是什么原因,待以后详细查看后再解决

 

旧代码

// 构造方法
   public SSLClient() throws Exception{
       // 调用父类构造方法
       super();  
       SSLContext ctx = SSLContext.getInstance("TLS");  
       X509TrustManager tm = new X509TrustManager() {  
               @Override  
               public void checkClientTrusted(X509Certificate[] chain,  
                       String authType) throws CertificateException {  
               }  
               @Override  
               public void checkServerTrusted(X509Certificate[] chain,  
                       String authType) throws CertificateException {  
               }  
               @Override  
               public X509Certificate[] getAcceptedIssuers() {  
                   return null;  
               }  
       };  
       ctx.init(null, new TrustManager[]{tm}, null);  
       SSLSocketFactory ssf = new SSLSocketFactory(ctx,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);  
       ClientConnectionManager ccm = this.getConnectionManager();  
       SchemeRegistry sr = ccm.getSchemeRegistry();  
       sr.register(new Scheme("https", 443, ssf));  
   }

新代码

public static CloseableHttpClient createSSLClientDefault(CookieStore cookieStore) {
SSLContext sslContext;
try {
    sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
        //信任所有
        @Override
        public boolean isTrusted(X509Certificate[] xcs, String string){
            return true;
        }
    }).build();

    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
    if(cookieStore == null){
        return HttpClients.custom().setSSLSocketFactory(sslsf).build();
    }else{
        return HttpClients.custom().setSSLSocketFactory(sslsf).setDefaultCookieStore(cookieStore).build();
    }
} catch (KeyStoreException ex) {
    logger.info(ex);
} catch (NoSuchAlgorithmException ex) {
    logger.info(ex);
} catch (KeyManagementException ex) {
    logger.info(ex);
}

return HttpClients.createDefault();

}

 

超时设置不生效问题

在查看相关文档的时候,发现有朋友说这个问题, 但是自己没有遇到过,所以暂时先不研究, 待研究后再写

 

测试完整代码, 不包括https

 

httpclient客户端访问测试代码

import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**

  • SocketTimeout 服务端链接成功后之间响应超时时间设置

  • ConnectTimeout 建立socket链接超时设置
    */
    public class TimeoutTestControllerTest {

    public static void main(String[] args) {
    try {
    //new TimeoutTestControllerTest().connectionTimeout();
    //new TimeoutTestControllerTest().socketTimeout();
    //new TimeoutTestControllerTest().socketTimeoutNo();
    new TimeoutTestControllerTest().connectionRequestTimeoutWithPoolingConnectionManager();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    /**

    • 1.ConnectTimeout:IP无法链接,链接超时 链接无法建立时间限制
    • @throws Exception
      */
      public void connectionTimeout() throws Exception {
      CloseableHttpClient httpclient = HttpClients.createDefault();
      HttpGet httpGet = new HttpGet(“http://74.125.203.100”);
      RequestConfig requestConfig = RequestConfig.custom()
      .setConnectionRequestTimeout(1000)
      .setSocketTimeout(1000) // 服务端相应超时
      .setConnectTimeout(5000) // 建立socket链接超时时间
      .build();
      httpGet.setConfig(requestConfig);
      long start = 0;
      try {
      start = System.currentTimeMillis();
      httpclient.execute(httpGet);
      System.out.println(“链接成功”);
      } catch (ConnectTimeoutException exception) {
      System.out.println(“链接成失败”);
      exception.printStackTrace();
      }
      long end = System.currentTimeMillis();
      System.out.println(“花费时间:” + (end-start)/1000 + “秒”);
      }

    /**

    • 2.socketTimeout测试,服务端没有指定时间内任何响应,会超时
    • @throws Exception
      */
      public void socketTimeout() throws Exception {
      CloseableHttpClient httpclient = HttpClients.createDefault();
      HttpGet httpGet = new HttpGet(“http://127.0.0.1:9999/testHttpClientTimeOutController/socket_timeout.do”);
      RequestConfig requestConfig = RequestConfig.custom()
      .setSocketTimeout(4000).build();
      httpGet.setConfig(requestConfig);
      long start = 0;
      try {
      start = System.currentTimeMillis();
      httpclient.execute(httpGet);
      } catch (SocketTimeoutException exception) {
      exception.printStackTrace();
      }
      long end = System.currentTimeMillis();
      System.out.println(“花费时间:” + (end-start)/1000 + “秒”);
      }

    /**

    • 3.socketTimeout测试:服务端隔800ms返回一点数据,不会超时

    • @throws Exception
      */
      public void socketTimeoutNo() {
      CloseableHttpClient httpclient = HttpClients.createDefault();
      HttpGet httpGet = new HttpGet(“http://127.0.0.1:9999/testHttpClientTimeOutController/socket_timeout_2.do”);
      RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(100)
      .setSocketTimeout(900).setConnectTimeout(100).build();
      httpGet.setConfig(requestConfig);

      long start = 0;
      try {
      start = System.currentTimeMillis();
      httpclient.execute(httpGet);
      CloseableHttpResponse response = httpclient.execute(httpGet);
      System.out.println(String.format(“socketTimeoutNo, %s”, EntityUtils.toString(response.getEntity())));
      } catch (Exception e) {
      e.printStackTrace();
      }
      long end = System.currentTimeMillis();
      System.out.println(“花费时间:” + (end-start)/1000 + “秒”);

    }

    /**

    • 4.connectionRequestTimeout测试:指从连接管理器(例如连接池)中拿到连接的超时时间

    • @throws Exception
      */
      public void connectionRequestTimeoutWithPoolingConnectionManager() throws Exception {
      PoolingHttpClientConnectionManager conMgr = new PoolingHttpClientConnectionManager();
      conMgr.setMaxTotal(2);

      final CloseableHttpClient httpclient = HttpClients.custom().setConnectionManager(conMgr).build();
      final HttpGet httpGet = new HttpGet(“http://127.0.0.1:9999/testHttpClientTimeOutController/connection_request_timeout.do”);

      RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(1000)
      .setConnectionRequestTimeout(1000).setSocketTimeout(1000).build();
      httpGet.setConfig(requestConfig);

      // 如下多线程占满连接池
      ExecutorService executorService = Executors.newFixedThreadPool(10);
      for (int i = 0; i < 10; i++) {
      executorService.submit(new Runnable() {
      @Override
      public void run() {
      try {
      CloseableHttpResponse response = httpclient.execute(httpGet);
      System.out.println(String.format(“connectionRequestTimeoutTest: %s”,
      EntityUtils.toString(response.getEntity())));
      } catch (SocketTimeoutException exception) {
      System.out.println(exception.getMessage());
      } catch (ClientProtocolException e) {
      e.printStackTrace();
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      });
      }

      // 在连接池占满的情况下,拿不到就会抛异常
      long start = 0;
      try {
      start = System.currentTimeMillis();
      CloseableHttpResponse response = httpclient.execute(httpGet);
      System.out.println(String.format(“connectionRequestTimeoutTest: %s”,
      EntityUtils.toString(response.getEntity())));
      } catch (Exception exception) {
      // 异常是从连接池拿到连接超时
      System.out.println(exception.getMessage());
      }
      long end = System.currentTimeMillis();
      System.out.println(“花费时间:” + (end-start)/1000 + “秒”);
      }

    /**

    • 5.connectionRequestTimeout测试,指从连接管理器中拿到连接的超时时间,由于使用基本的连接管理器,链接被占用时,直接无法分配链接

    • connectionRequestTimeout并未生效,目前看来该参数只在连接池奏效.

    • 该链接管理器(BasicHttpClientConnectionManager)是单线程情况下可以使用,多线程情况下不要使用。

    • @throws Exception
      */
      public void connectionRequestTimeoutWithBasicConnectionManager() throws Exception {

      BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager();
      final CloseableHttpClient httpclient = HttpClients.custom()
      .setConnectionManager(connManager).setMaxConnPerRoute(1).build();
      final HttpGet httpGet = new HttpGet(“http://127.0.0.1:8080/test/connection_request_timeout”);

      RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(100000)
      .setConnectionRequestTimeout(1000000).setSocketTimeout(1000000).build();
      httpGet.setConfig(requestConfig);

      // 如下多线程占满连接
      ExecutorService executorService = Executors.newFixedThreadPool(10);
      for (int i = 0; i < 10; i++) {
      executorService.submit(new Runnable() {
      @Override
      public void run() {
      CloseableHttpResponse response = null;
      try {
      response = httpclient.execute(httpGet);
      System.out.println(String.format(“connectionRequestTimeoutTest: %s”,
      EntityUtils.toString(response.getEntity())));
      } catch (Exception exception) {
      exception.printStackTrace();
      } finally {
      if (response != null) {
      try {
      response.close();
      httpclient.close();
      } catch (IOException e) {
      e.printStackTrace();
      }
      }

               }
           }
       });
      

      }
      System.out.println(new Date());

      // 在连接池占满的情况下,拿不到就会抛异常
      try {
      CloseableHttpResponse response = httpclient.execute(httpGet);
      System.out.println(String.format(“connectionRequestTimeoutTest: %s”,
      EntityUtils.toString(response.getEntity())));
      } catch (Exception exception) {
      System.out.println(new Date());
      exception.printStackTrace();
      // 异常是从连接池拿到连接超时
      System.out.println(exception.getMessage());
      }

    }

}

 

服务端代码  用于测试长时间响应

import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**

  • 测试HttpClient链接超时机制
    */
    @Controller
    @RequestMapping(“testHttpClientTimeOutController”)
    public class TestHttpClientTimeOutController {

    private static final Logger logger = Logger.getLogger(TestHttpClientTimeOutController.class);

    /**

    • 1.测试socketOutTimeout,三秒后返回数据
    • @return
    • @throws InterruptedException
      */
      @RequestMapping(value = {"/socket_timeout"}, method = {RequestMethod.GET})
      @ResponseBody
      String socketTimeout() throws InterruptedException {
      logger.info(“socket_timeout”);
      Thread.sleep(3000);
      return “socket_timeout”;
      }

    /**

    • 2.测试socketOutTimeout,每隔0.8秒返回数据
    • @return
    • @throws InterruptedException
      */
      @RequestMapping(value = {"/socket_timeout_2"}, method = {RequestMethod.GET})
      void socketTimeout2(HttpServletResponse response) throws InterruptedException, IOException {
      logger.info(“socket_timeout_2”);
      for (int i = 0; i < 10; i++) {
      logger.info("{}" + i);
      response.getWriter().println("" + i);
      response.flushBuffer();
      Thread.sleep(800);
      }
      }

    /**

    • 3.测试connectionRequestTimeout用的服务,三秒后返回数据
    • @param request
    • @return
    • @throws InterruptedException
      */
      @RequestMapping(value = {"/connection_request_timeout"}, method = {RequestMethod.GET})
      @ResponseBody
      String connectionRequestTimeout(HttpServletRequest request) throws InterruptedException {
      logger.info(request.getRequestURI());
      Thread.sleep(3000);
      return “connectionRequestTimeout”;
      }
      }

转载来源:https://blog.csdn.net/du771278794/article/details/83008867

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
http工具类:package com.tpl.util; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; /** * */ public class HttpClientUtil { public static void main(String arg[]) throws Exception { String url = "http://xxx/project/getxxx.action"; JSONObject params= new JSONObject(); List res=new ArrayList(); JSONObject params1 = new JSONObject(); // params1.put("code", "200"); // params1.put("phone", "13240186028"); res.add(params1); params.put("result", res); String ret = doPost(url, params).toString(); System.out.println(ret); } /** httpClient的get请求方式2 * @return * @throws Exception */ public static String doGet(String url, String charset) throws Exception { /* * 使用 GetMethod 来访问一个 URL 对应的网页,实现步骤: 1:生成一个 HttpClinet 对象并设置相应的参数。 * 2:生成一个 GetMethod 对象并设置响应的参数。 3:用 HttpClinet 生成的对象来执行 GetMethod 生成的Get * 方法。 4:处理响应状态码。 5:若响应正常,处理 HTTP 响应内容。 6:释放连接。 */ /* 1 生成 HttpClinet 对象并设置参数 */ HttpClient httpClient = new HttpClient(); // 设置 Http 连接超时为5秒 httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(5000); /* 2 生成 GetMethod 对象并设置参数 */ GetMethod getMethod = new GetMethod(url); // 设置 get 请求超时为 5 秒

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值