HttpClient详细执行原理

一、HttpClient使用步骤分析

HttpCLient最关键的方法是执行HTTP请求的方法execute。只要把HTTP请求传入,就可以得到HTTP响应

用HttpClient请求一个Http请求的步骤为

(1)创建一个HttpClient对象
(2)创建一个Request对象
(3)使用HttpClient来执行Request请求,得到对方的response
(4)处理response
(5)关闭HttpClient

下边根据这几个步骤,进行详细步骤分析 

1.1、创建一个HttpClient对象

HttpClient的实现类为CloseableHttpClient。创建CloseableHttpClient实例有两种方式(不使用SpringBoot-RestTemplate场景):

1.1.1、使用CloseableHttpClient的工厂类HttpClients:如HttpClients.createDefault()

        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(100);

        // 设置请求和传输超时时间
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout)
            .setConnectTimeout(connectTimeout).build();

        CloseableHttpClient httpclient = HttpClients.custom().setConnectionManager(cm)
            .setDefaultRequestConfig(requestConfig).build();

1.1.2、使用CloseableHttpClient的builder类HttpClientBuilder:

先对一些属性进行配置(采用装饰者模式,不断的.setxxxxx().setxxxxxxxx()就行了),再调用build方法来创建实例。

上面(1)的HttpClients.createDefault()实际上调用的也就是HttpClientBuilder.create().build()。

build()方法最终是根据各种配置来new一个InternalHttpClient实例(CloseableHttpClient实现类)

InternalHttpClient底层实现了:HttpCLientConnectionManager、HttpRoutePlanner和RequestConfig,下边分别介绍

(1)HttpCLientConnectionManager:HTTP连接管理器介绍

作用:它负责新HTTP连接的创建、管理连接的生命周期还有保证一个HTTP连接在某一时刻只被一个线程使用

原理:在内部实现的时候,manager使用一个ManagedHttpClientConnection的实例来作为一个实际connection的代理,负责管理connection的状态以及执行实际的I/O操作。如果一个被监管的connection被释放或者被明确关闭,尽管此时manager仍持有该连接的代理,但是这个connection的状态不会被改变也不能再执行任何的I/O操作

两种具体实现:

1、BasicHttpClientConnectionManager

每次只管理一个connection,所以只能被一个线程使用。它在管理连接的时候如果发现有相同route的请求,会复用之前已经创建的连接,如果新来的请求不能复用之前的连接,它会关闭现有的连接并重新打开它来响应新的请求

2、PoolingHttpClientConnectionManager(多线程的,默认实现)

默认不对HttpClientBuilder进行配置的话,new出来的CloeableHttpClient实例使用的是PoolingHttpClientConnectionManager

管理着一个连接池,以同时为多个线程服务。每次新来一个请求,如果在连接池中已经存在route相同并且可用的connection,连接池就会直接复用这个connection;当不存在route相同的connection,就新建一个connection为之服务;如果连接池已满,则请求会等待直到被服务或者超时

setMaxPerRoute(默认值20):总的最大连接数量

方法和setMaxTotal(默认值200):每个route的最大连接数量

如果所有的连接请求都是到同一个url,那可以把MaxPerRoute的值设置成和MaxTotal一致,这样就能更高效地复用连接

(2)HttpRoutePlanner:HttpClient复杂的路由策略以及代理介绍

ttpRoutePlanner是基于http上下文情况下,客户端到服务器的路由计算策略,一般没有代理的话,就不用设置这个东西。这里有一个很关键的概念—Route:在HttpClient中,一个Route指运行环境机器->目标机器host的一条线路,也就是如果目标url的host是同一个,那么它们的route也是一样的

(3)RequestConfig:对request的一些配置

里面比较重要的有三个超时时间,默认的情况下这三个超时时间都为0(如果不设置request的Config,会在execute的过程中使用HttpClientParamConfig的getRequestConfig中用默认参数进行设置),这也就意味着无限等待,很容易导致所有的请求阻塞在这个地方无限期等待。这三个超时时间为:

a、connectionRequestTimeout—从连接池中取连接的超时时间

b、connectTimeout—连接超时时间

c、socketTimeout—请求超时时间

例子:

        // 设置请求和传输超时时间
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout)
            .setConnectTimeout(connectTimeout).build();

1.2、创建一个Request对象

HttpClient支持所有的HTTP1.1中的所有定义的请求类型:GET、HEAD、POST、PUT、DELETE、TRACE和OPTIONS。对使用的类为HttpGet、HttpHead、HttpPost、HttpPut、HttpDelete、HttpTrace和HttpOptions。

一个Request还可以addHeader、setEntity、setConfig等

1.3、执行Request请求

执行Request请求就是调用HttpClient的execute方法。最简单的使用方法是调用execute(final HttpUriRequest request)。

HttpContext是跟一个连接相关联的,所以它也只能属于一个线程,如果没有特别设定,在execute的过程中,HttpClient会自动为每一个connection   new一个HttpClientHttpContext。

一个execute执行流程

  • new一个http context
  • 取出Request和URL
  • 根据HttpRoute的配置看是否需要重写URL
  • 根据URL的host、port和scheme设置target
  • 在发送前用http协议拦截器处理request的各个部分
  • 取得验证状态、user token来验证身份
  • 从连接池中取一个可用的连接
  • 根据request的各种配置参数以及取得的connection构造一个connManaged
  • 打开managed的connection(包括创建route、dns解析、绑定socket、socket连接等)
  • 请求数据(包括发送请求和接收response两个阶段)
  • 查看keepAlive策略,判断连接是否要复用,并设置相应标识
  • 返回response
  • 用http协议拦截器处理response的各个部
     

 

 

 

 

 

 

参考资料

https://www.jianshu.com/p/14c005e9287c

你可能感兴趣的:(网络编程)