本篇主要总结在HttpClient使用过程中的最佳实践、注意点以及踩到的坑。
包含连接池的HttpClient
|
|
注意点:
- 可以理解为
setDefaultMaxPerRoute
针对单个IP,setMaxTotal
针对所有请求 setKeepAliveStrategy
可以自定义TCP连接KeepAlive的时间。但是需要注意的是,如果TCP连接在池中空闲的期间到期了,那么即使Server端关闭连接,Client端的这个TCP socket也感知不到。此时Server处于CLOSE_WAIT
状态,知道TCP Socket从池中被唤醒或者超过CLOSE_WAIT时间或者被池自己关掉。当TCP被唤醒时,C端会感知到S端的关闭连接操作,因此会关闭这个TCP链路,重新建立一条链路发送下一次请求。(等于说每次request之前都会检查一下从池中取出的TCP链路是否有效,通过这个机制来保证不会出现C端拿着无效的TCP链路去请求)但是同样,以上的机制可能会导致S端有很多的CLOSE_WAIT
状态,严重时可能造成Socket耗尽,这点需要注意。closeIdleConnectionsPeriodically
是自定义函数,可以定时关闭连接池中长时间不用的连接
发送request的几种方法和注意点
推荐的方式
|
|
这种方式下,HttpClient将会替你回收连接。这里用回收而不是销毁,是因为HttpClient在默认的情况下,是会进行连接复用的。
自行控制的方式
|
|
调用method.releaseConnection();
释放了connection使得connection对于HttpClient而言重新可用,而非真正的关闭该connection,原因在于使用了Http1.1协议,HttpClient可以在同一个connection中批量发送后续的请求。
自行控制的方式2
|
|
注意:必须要在finally块中调用resp.close()
,否则这次请求会一直占用连接,不会被回收。而默认的情况下,一个正常new出来的HttpClient实例只会给一个route留2个connection [1],因此一旦没有关闭,那么在多线程的情况下,上面的代码至多只能执行2次就会阻塞。
另一种释放连接的方法是:调用EntityUtils.consume(resp);
,该函数内部会调用resp.close()
从而释放连接。但是需要注意的是这种方式存在安全隐患,要明确resp不会过大或者是恶意的应答,从而挤爆缓冲区。最好能判断一下resp的大小,对于明显过大的应答要进行过滤。
取消request
|
|