1、HttpClient简介

HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性,它不仅使客户端发送Http请求变得容易,而且也方便开发人员测试接口(基于Http协议的),提高了开发的效率,也方便提高代码的健壮性。因此熟练掌握HttpClient是很重要的必修内容,掌握HttpClient后,相信对于Http协议的了解会更加深入。

org.apache.commons.httpclient.HttpClient与org.apache.http.client.HttpClient的区别Commons的HttpClient项目现在是生命的尽头,不再被开发,  已被Apache HttpComponents项目HttpClient和HttpCore  模组取代,提供更好的性能和更大的灵活性。

2、HTTP的Keep-Alive

在前面的博客中http协议中,可以看到http的请求头中可以设置connection可以设置为Keep-Alive,在HTTP/1.1使用Keep-Alive为默认值,如果需要关闭则需要手动关闭。

在HTTP 1.0以前,每个http请求都要求打开一个TCP socket连接,并且使用一次之后就断开这个TCP连接,这会导致频繁地创建和销毁TCP。HTTP 1.1通过使用keep-alive可以改善这种状态,即在一次TCP连接中可以持续发送多份数据而不会断开连接,以此提高性能和提高http服务器的吞吐率(更少的tcp连接意味着更少的系统内核调用,socket的accept()和close()调用)。

2.1 HTTP的Keep-Alive

当保持长连接时,如何判断一次请求已经完成?
Content-Length
Content-Length表示实体内容的长度。浏览器通过这个字段来判断当前请求的数据是否已经全部接收。
所以,当浏览器请求的是一个静态资源时,即服务器能明确知道返回内容的长度时,可以设置Content-Length来控制请求的结束。但当服务器并不知道请求结果的长度时,如一个动态的页面或者数据,Content-Length就无法解决上面的问题,这个时候就需要用到Transfer-Encoding字段。

Transfer-Encoding
Transfer-Encoding是指传输编码,在上面的问题中,当服务端无法知道实体内容的长度时,就可以通过指定Transfer-Encoding: chunked来告知浏览器当前的编码是将数据分成一块一块传递的。当然, 还可以指定Transfer-Encoding: gzip, chunked表明实体内容不仅是gzip压缩的,还是分块传递的。最后,当浏览器接收到一个长度为0的chunked时, 知道当前请求内容已全部接收。

Keep-Alive timeout:
Httpd守护进程,一般都提供了keep-alive timeout时间设置参数。比如nginx的keepalive_timeout,和Apache的KeepAliveTimeout。这个keepalive_timout时间值意味着:一个http产生的tcp连接在传送完最后一个响应后,还需要hold住keepalive_timeout秒后,才开始关闭这个连接。
当httpd守护进程发送完一个响应后,理应马上主动关闭相应的tcp连接,设置 keepalive_timeout后,httpd守护进程会想说:”再等等吧,看看浏览器还有没有请求过来”,这一等,便是keepalive_timeout时间。如果守护进程在这个等待的时间里,一直没有收到浏览器发过来http请求,则关闭这个http连接。

2.2 Tcp的Keep-Alive

tcp链接建立之后,如果应用程序或者上层协议一直不发送数据,或者隔很长时间才发送一次数据,当链接很久没有数据报文传输时如何去确定对方还在线,到底是掉线了还是确实没有数据传输,链接还需不需要保持,这种情况在TCP协议设计中是需要考虑到的。
TCP协议通过一种巧妙的方式去解决这个问题,当超过一段时间之后,TCP自动发送一个数据为空的报文给对方,如果对方回应了这个报文,说明对方还在线,链接可以继续保持,如果对方没有报文返回,并且重试了多次之后则认为链接丢失,没有必要保持链接。

2.3 http keep-alive与tcp keep-alive

HTTP位于网络协议栈的应用层,而TCP位于网络协议栈的传输层,两者的KEEP-ALIVE虽然名称相同,但是作用不同。http keep-alive是为了让tcp活得更久一点,以便在同一个连接上传送多个http,提高socket的效率。而tcp keep-alive是TCP的一种检测TCP连接状况的保鲜机制。t检测对端是否依然存活。

2.4 开启Keep-Alive的优缺点

优点:Keep-Alive模式更加高效,因为避免了连接建立和释放的开销。

缺点:长时间的Tcp连接容易导致系统资源无效占用,浪费系统资源。

所以对于需要频繁发送HTTP请求的应用,需要在客户端开启keep-alive,使用HTTP长连接。

3 HttpClient设置

httpClient = HttpClients.custom()
//连接池配置
.setConnectionManager(poolingHttpClientConnectionManager)
//requestConfig配置
.setDefaultRequestConfig(requestConfig)
.disableCookieManagement()
.disableConnectionState()
.disableAuthCaching()
//默认socketConfig配置
.setDefaultSocketConfig(socketConfig)
//默认头配置
.setDefaultHeaders(defaultHeaders)
//重试handle
.setRetryHandler(httpRequestRetryHandler)
.build();

3.1 PoolingHttpClientConnectionManager连接池设置

两个主机建立连接的过程是很复杂的一个过程,涉及到多个数据包的交换,并且也很耗时间。Http连接需要的三次握手开销很大,这一开销对于比较小的http消息来说更大。但是如果我们直接使用已经建立好的http连接,这样花费就比较小,吞吐率更大。在高并发大量的请求网络的时候,使用连接池能提升吞吐量。

 PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
// 设置整个连接池的最大连接数
cm.setMaxTotal(maxTotal);
// 设置每个route默认的最大连接数
cm.setDefaultMaxPerRoute(maxPerRoute);
HttpHost httpHost = new HttpHost(hostname, port);
// 设置某个route的最大连接数,优先于defaultMaxPerRoute。
cm.setMaxPerRoute(new HttpRoute(httpHost), maxRoute);
//该方法关闭超过连接保持时间的连接,并从池中移除。
cm.closeExpiredConnections();
//该方法关闭空闲时间超过timeout的连接,空闲时间从交还给连接池时开始,不管是否已过期,超过空闲时间则关闭。
cm.closeIdleConnections(timeout,tunit);
connectionConfig配置
//消息约束
MessageConstraints messageConstraints = MessageConstraints.custom()
.setMaxHeaderCount(200)
.setMaxLineLength(2000)
.build();
//Http connection相关配置
ConnectionConfig connectionConfig = ConnectionConfig.custom()
.setMalformedInputAction(CodingErrorAction.IGNORE)
.setUnmappableInputAction(CodingErrorAction.IGNORE)
.setCharset(Consts.UTF_8)
.setMessageConstraints(messageConstraints)
.build();
//一般不修改HTTP connection相关配置,故不设置
//cm.setDefaultConnectionConfig(connectionConfig);
//cm.setConnectionConfig(new HttpHost("somehost", 80), ConnectionConfig.DEFAULT);

具体源码解析可参考:https://www.cnblogs.com/shoren/p/httpclient-leaseConnection.html

3.2 RequestConfig设置

主要用于获取和配置一些外部的网络环境

RequestConfig requestConfig = RequestConfig.custom()
//设置从connectManager获取Connection 超时时间
.setConnectionRequestTimeout(1000)
//设置连接超时时间
.setConnectTimeout(10000)
//请求获取数据的超时时间
.setSocketTimeout(10000)
//确定是否应自动处理身份验证
.setAuthenticationEnabled(true)
//确定循环重定向(重定向到相同位置)是否应该重定向
.setCircularRedirectsAllowed(false)
//重定向的最大数目。对重定向次数的限制是为了防止无限循环
.setMaxRedirects(5)
//确定是否应自动处理重定向
.setRedirectsEnabled(true)
//确定是否应拒绝相对重定向。HTTP规范要求位置值是一个绝对URI
.setRelativeRedirectsAllowed(true)
//确定是否应自动解压缩压缩实体
.setContentCompressionEnabled(true)
//确定用于HTTP状态管理的cookie规范的名称
.setCookieSpec("")
//返回用于请求执行的本地地址。在具有多个网络接口的计算机上,此参数可用于选择其中的网络接口连接产生。
.setLocalAddress()
//代理配置
.setProxy()
//在使用代理主机进行身份验证时,确定支持的身份验证方案的优先顺序。
.setProxyPreferredAuthSchemes()
//在使用目标主机进行身份验证时,确定受支持的身份验证模式的首选项顺序
.setTargetPreferredAuthSchemes()
.build();

3.3 SocketConfig配置

 SocketConfig.custom()
//开启监视TCP连接是否有效
.setSoKeepAlive(false)
//是否可以在一个进程关闭Socket后,即使它还没有释放端口,其它进程还可以立即重用端口
.setSoReuseAddress(true)
//接收数据的等待超时时间,单位ms
.setSoTimeout(10000)
//是否立即发送数据,设置为true会关闭Socket缓冲,默认为false
.setTcpNoDelay(false)
.build();

3.4 defaultHeader配置

Collection<Header> defaultHeaders = new ArrayList<>();
defaultHeaders.add(new BasicHeader(HttpHeaders.ACCEPT_ENCODING, "gzip, deflate"));
defaultHeaders.add(new BasicHeader(HttpHeaders.ACCEPT_LANGUAGE, "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3"));
defaultHeaders.add(new BasicHeader(HttpHeaders.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"));
defaultHeaders.add(new BasicHeader(HttpHeaders.CONNECTION, "keep-alive"));

3.5 HttpRequestRetryHandler配置

//禁用重试(参数:retryCount、requestSentRetryEnabled)
HttpRequestRetryHandler requestRetryHandler = new DefaultHttpRequestRetryHandler(0, false);
//自定义重试策略
httpRequestRetryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(IOException exception,int executionCount, HttpContext context) {
if (executionCount >= 3) {// 如果已经重试了3次,就放弃
return false;
}
if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接,那么就重试
return true;
}
if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
return false;
}
if (exception instanceof InterruptedIOException) {// 超时
return false;
}
if (exception instanceof UnknownHostException) {// 目标服务器不可达
return false;
}
if (exception instanceof ConnectTimeoutException) {// 连接被拒绝
return false;
}
if (exception instanceof SSLException) {// SSL握手异常
return false;
}
return false;
}
}

其实我们在实际使用中也是使用默认的 socketConfig 和 connectionConfig。在实际应用中连接数相关配置(如maxTotal、maxPerRoute),还有请求相关的超时时间设置(如connectionTimeout、socketTimeout、connectionRequestTimeout)是比较重要的。

具体连接池原理参考文档:

HttpClient 4.3连接池参数配置及源码解读

httpClient 4.3.x configuration 官方样例

使用httpclient必须知道的参数设置及代码写法、存在的风险

HttpClient连接池的连接保持、超时和失效机制

HttpClient连接池原理及一次连接时序图

---恢复内容结束---

httpclient解析的更多相关文章

  1. .NET手记-HttpClient解析GB2312乱码问题

    最近为App的服务器端卸了个爬虫程序,输出结果时发现出现乱码现象,尝试使用了几个方案发现效果并不太好,最后发现了一个很简单的用法. var result = await client.GetByteA ...

  2. httpclient 解析excel

    http://www.blogjava.net/jayslong/archive/2011/04/21/convert_xls_and_xlsx_to_csv.html 分享用Java将Excel的x ...

  3. HttpClient学习记录-系列1(tutorial)

    1. HttpClient使用了facade模式,如何使用的? 2. HTTP protocol interceptors使用了Decorator模式,如何使用的? URIBuilder respon ...

  4. (一)问候 HtmlUnit

    第一节: HtmlUnit 简介 htmlunit 是一款开源的java 页面分析工具,读取页面后,可以有效的使用htmlunit分析页面上的内容.项目可以模拟浏览器运行,被誉为java浏览器的开源实 ...

  5. laravel核心思想

    服务容器.依赖注入.门脸模式 服务容器 容器概念 用来装一个个实例的对象,比如邮件类. IOC控制反转 IOC(Inversion of Control)控制反转,面向对象,可降低代码之间的耦合度,借 ...

  6. HTTP+XML接口客户端 结合策略模式实现总结

    在项目中,我们经常会使用到http+xml的接口,而且不仅仅的是一个,可能会有多个http的接口需要实时的交互.但是http接口的发送消息的公共部分是一样的,只有每个接口的报文解析和返回报文是不同的, ...

  7. http接口服务方结合策略模式实现总结

    在项目中,我们经常会使用到http+xml的接口,而且不仅仅的是一个,可能会有多个http的接口需要实时的交互.但是http接口的接收消息的公共部分是一样的,只有每个接口的报文解析和返回报文是不同的, ...

  8. 小记---------网页采集之Jsoup

        Jsoup是一款Java解析器,相当于httpClient解析器 功能:①:从一个URL,文件或字符串中解析HTML         ②:使用DOM或CSS选择器来查找.取出数据       ...

  9. 使用HttpClient来异步发送POST请求并解析GZIP回应

    .NET 4.5(C#): 使用HttpClient来异步发送POST请求并解析GZIP回应 在新的C# 5.0和.NET 4.5环境下,微软为C#加入了async/await,同时还加入新的Syst ...

随机推荐

  1. 429 too many requests错误出现在wordpress后台更新及官网的5种解决方法

    从今年10月份开始wordpress服务经常出现429 too many requests错误,包括后台更新和访问wp官网,如下图所示,这是为什么呢?怎么处理呢?有大佬向官方论坛提问了,论坛主持人Ja ...

  2. python27期day12:推导式、内置函数、高阶函数、匿名函数、作业题

    1.推导式:做一些有规律的数据结构 列表推导式: 普通循环模式: [加工后的变量 for 循环] 示例一:print([i for i in range(1,51)]) 结果:[1, 2, 3, 4, ...

  3. 【Spring IoC】BeanFactory 和 ApplicationContext(五)

    一.BeanFactory容器 BeanFactory 容器是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持,这个容器接口在 org.springframework.beans.fac ...

  4. wafer2的keng

    一.之前用wafer2开发的小程序,今天突然Error: 用户未登录过,请先使用 login() 登录? 答:改用qcloud.login, 替换掉qcloud.loginWithCode (小程序代 ...

  5. 【oracle】迁表结构和数据

    背景:把一些表和数据从某库迁到另一个库 1.命令框: exp yktsh/yktsh_2019@orcl30 file=d:\yktsh20191201.dmp log=d:\daochu; exp ...

  6. vue项目的安装与启动

      第一步:安装Node 检测Node是否安装成功 node -v 第二步:安装vue-cli     命令:npm install vue-cli -g 第三步:搭建项目命令 vue init we ...

  7. 微信小程序特性总结

    一. 小程序不是运行在浏览器中, 所以没有BOM和DOM对象 即console.log(window)和console.log(document)是获取不到任何内容的 二. 小程序特有的额外js成员( ...

  8. vector的基本操作

    vector怎么删除元素? #include<iostream> #include<vector> using namespace std; int main() { vect ...

  9. 清北学堂(2019 5 3) part 6

    今天讲STL 1.pair——<algorithm> 声明形如pair<int,int> x;(不是int也可以),表示x有前后两个成员,都是int类型,调用时写x.first ...

  10. [LeetCode] 75. Sort Colors 颜色排序

    Given an array with n objects colored red, white or blue, sort them in-place so that objects of the ...