httpClient用法

1、httpClient
HttpClient是Apache中的一个开源的项目。它实现了HTTP标准中Client端的所有功能,使用它能够很容易地进行HTTP信息的传输。它的各个版本的使
用方式都不太一样,我使用的版本是4.3.5的,网上比较多的资源是3.+版本的,目前最新已经有4.4+版本了,感兴趣的都可以看一下。
HttpCLient最关键的方法是执行HTTP请求的方法execute。只要把HTTP请求传入,就可以得到HTTP响应。
使用HttpClient请求一个Http请求的步骤为:
(1)创建一个HttpClient对象
(2)创建一个Request对象
(3)使用HttpClient来执行Request请求,得到对方的response
(4)处理response
(5)关闭HttpClient

2、创建一个HttpClient对象
目前最新版的HttpClient的实现类为CloseableHttpClient。创建CloseableHttpClient实例有两种方式:
(1)使用CloseableHttpClient的工厂类HttpClients的方法来创建实例。HttpClients提供了根据各种默认配置来创建CloseableHttpClient实例的快
捷方法。最简单的实例化方式是调用HttpClients.createDefault()。
(2)使用CloseableHttpClient的builder类HttpClientBuilder,先对一些属性进行配置(采用装饰者模式,不断的.setxxxxx().setxxxxxxxx()就行
了),再调用build方法来创建实例。上面的HttpClients.createDefault()实际上调用的也就是HttpClientBuilder.create().build()。
build()方法最终是根据各种配置来new一个InternalHttpClient实例(CloseableHttpClient实现类)。

3、创建一个Request对象
HttpClient支持所有的HTTP1.1中的所有定义的请求类型:GET、HEAD、POST、PUT、DELETE、TRACE和OPTIONS。对使用的类为HttpGet、HttpHead、
HttpPost、HttpPut、HttpDelete、HttpTrace和HttpOptions。Request的对象建立很简单,一般用目标url来构造就好了。下面是一个HttpPost的创建
代码:
HttpPost httpPost = new HttpPost(someGwUrl);
一个Request还可以addHeader、setEntity、setConfig等,一般这三个用的比较多。

4、执行Request请求
执行Request请求就是调用HttpClient的execute方法。最简单的使用方法是调用execute(final HttpUriRequest request)。
HttpClient允许http连接在特定的Http上下文中执行,HttpContext是跟一个连接相关联的,所以它也只能属于一个线程,如果没有特别设定,在
execute的过程中,HttpClient会自动为每一个connection  new一个HttpClientHttpContext。
HttpClientContext localcontext = HttpClientContext.adapt(context != null ? context : new BasicHttpContext()

5、处理response
HttpReaponse是将服务端发回的Http响应解析后的对象。CloseableHttpClient的execute方法返回的response都是CloseableHttpResponse类型。可以
getFirstHeader(String)、getLastHeader(String)、headerIterator(String)取得某个Header name对应的迭代器、getAllHeaders()、getEntity
、getStatus等,一般这几个方法比较常用。
在这个部分中,对于entity的处理需要特别注意一下。
一般来说一个response中的entity只能被使用一次,它是一个流,这个流被处理完就不再存在了。
先response.getEntity()再使用HttpEntity#getContent()来得到一个java.io.InputStream,然后再对内容进行相应的处理。
有一点非常重要,想要复用一个connection就必须要让它占有的系统资源得到正确释放。释放资源有两种方法:
a、关闭和entity相关的content stream

如果是使用outputStream就要保证整个entity都被write out,如果是inputStream,则再最后要记得调用inputStream.close()。或者使用
EntityUtils.consume(entity)或EntityUtils.consumeQuietly(entity)来让entity被完全耗尽(后者不抛异常)来做这一工作。EntityUtils中有个
toString方法也很方便的(调用这个方法最后也会自动把inputStream close掉的),不过只有在可以确定收到的entity不是特别大的情况下才能使用

做过实验,如果没有让整个entity被fully consumed,则该连接是不能被复用的,很快就会因为在连接池中取不到可用的连接超时或者阻塞在这里(
因为该连接的状态将会一直是leased的,即正在被使用的状态)。所以如果想要复用connection,一定一定要记得把entity fully consume掉,只要
检测到stream的eof,是会自动调用ConnectionHolder的releaseConnection方法进行处理的(注意,ConnectionHolder并不是一个public class,虽
然里面有一些跟释放连接相关的重要操作,但是却无法直接调用)。
b、关闭response
执行response.close()虽然会正确释放掉该connection占用的所有资源,但是这是一种比较暴力的方式,采用这种方式之后,这个connection就不能
被重复使用了。

6、关闭HttpClient
调用httpClient.close()会先shut down connection manager,然后再释放该HttpClient所占用的所有资源,关闭所有在使用或者空闲的connection
包括底层socket。由于这里把它所使用的connection manager关闭了,所以在下次还要进行http请求的时候,要重新new一个connection manager来
build一个HttpClient(也就是在需要关闭和新建Client的情况下,connection manager不能是单例的)。

7、其他一些东西
(1)关于keep-alive
在HttpClient.execute得到response之后的相关代码中,它会先取出response的keep-alive头来设置connection是否resuable以及存活的时间。如果
服务器返回的响应中包含了Connection:Keep-Alive(默认有的),但没有包含Keep-Alive时长的头消息,HttpClient认为这个连接可以永远保持。
(2)连接池管理
前面也有说到关于从连接池中取可用连接的部分逻辑。完整的逻辑是:在每收到一个route请求后,连接池都会建立一个以这个route为key的子连接池
,当有一个新的连接请求到来的时候,它会优先匹配已经存在的子连接池们,如果之前已经有过以这个route为key的子连接池,那么就会去试图取这
个子连接池中状态为available的连接,如果此时有可用的连接,则将取得的available连接状态改为leased的,取连接成功。如果此时子连接池没有
可用连接,那再看是否达到了所设置的最大连接数和每个route所允许的最大连接数的上限,如果还有余量则new一个新的连接,或者取得
lastUsedConnection,关闭这个连接、把连接从原来所在的子连接池删除,再lease取连接成功。如果此时的情况不允许再new一个新的连接,就把这
个请求连接的请求放入一个queue中排队等待,直到得到一个连接或者超时才会从queue中删去。
一个连接被release之后,会从等待连接的queue中唤醒等待连接的服务进行处理。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值