HttpClient使用心得
做过Java web开发的朋友们,应该大部分都用过Apatch HttpClient工具类库,最近在维护公司一个老项目时,遇到了由于HttpClient使用不当导致的线上问题,针对这些问题总结了一些心得,分享给大家,如有不正确的地方欢迎留言指出。
1、尽量复用HttpClient对象
初学者一般使用HttpClient工具,都是newHttpClient()对象出来,然后结合相关的HttpMethod对象执行Http请求操作,如下实例代码:
HttpClient client = new HttpClient();
String responseStr = null;
try {
intstatusCode = client.executeMethod(method);
if(statusCode != HttpStatus.SC_OK) {
log.error("服务器{},返回码异常{}", url, statusCode);
}else {
InputStream inputStream = method.getResponseBodyAsStream();
StringBuilder sBuilder = newStringBuilder();
charbuf[] = new char[1024];
intreadNum;
while(-1 != (readNum = is.read(buf, 0, BUF_LEN))) {
sBuilder.append(buf,0, readNum);
}
//获取服务器返回的内容
responseStr= sBuilder.toString();
}
} catch (HttpException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
method.releaseConnection();
}
当应用系统多个模块需要执行Http请求时,若按照上述例子实现代码,会存在多份类似的代码,应用并发运行时,可能存在同时实例化多个HttpClient实例的情况,会造成系统资源的浪费,Apatch官方的性能指导文档建议可以根据系统实际请求情况,全应用共用一个单例HttpClient对象或每个组件的请求共用一个HttpClient对象。
当共用一个HttpClient对象时,需要考虑并发场景,避免造成多线程问题。在公司的系统就遇到这样一个问题,概率存在Http请求执行失败的情况,查看日志发现报各种奇怪的异常,有java.net.SocketException: Connection reset、java.io.IOException:CRLF expected at end of chunk、java.io.IOException: Bad chunk size等,一时不知所措,再细看日志发现出异常前存在如下警告日志:“SimpleHttpConnectionManager being used incorrectly. Be sure that HttpMethod.releaseConnection()is always called and that only one thread and/or method is using thisconnection manager at a time.”,大概的意思是SimpleHttpConnectionManager只适用于单线程场景,查资料发现当用不带参数的构造函数实例化HttpClient对象时,内部会实例化一个SimpleHttpConnectionManager对象,该连接管理对象没有采用连接池的方式管理HttpConnection对象,仅管理一个HttpConnection对象,不能适用于多线程场景,在多线程场景下SimpleHttpConnectionManager不能保证每个线程获取到单独的HttpConnection对象,因此易造成多个线程共用HttpConnection对象的情况,从而造成HttpConnection对象操作异常。从公司日志看出连续两次Http请求方法执行的时间间隔很短时(比如几十ms),会出现上述异常。HttpClient工具包中提供了一个MultiThreadedHttpConnectionManager类,可用于多线程场景下的Http连接,在实例化HttpClient对象时,在构造函数中传递MultiThreadedHttpConnectionManager对象,MultiThreadedHttpConnectionManager类以连接池的方式管理HttpConnection,确保每个HttpMethod方法执行时获取独立的HttpConnection对象,避免多线程问题。
当以默认的构造函数实例化非单例的HttpClient对象时,当请求执行完成时不再需要该HttpClient对象时,需要及时关闭HttpMethod使用到的HttpConnection对象。通常情况下都是调用HttpMethod.releaseConnection()方法释放方法对象占用的连接,通过跟踪该方法的代码,发现该方法仅仅是将HttpConnection对象归还给SimpleHttpConnectionManager,并未执行HttpConnection的close方法关闭底层的TCP连接,可以通过HttpClient对象获取SimpleHttpConnectionManager对象,并调用其closeIdleConnections方法关闭连接。
2、学会设置HttpClient连接相关参数
3、避免在数据库事务方法中使用耗时的请求操作
在数据库事务方法中,需要避免使用耗时的请求操作,避免导致事务超时异常。公司的应用就遇到一个这样的问题:第三方平台退款接口异常,导致退款事务超时,实际退款完成了,但是将退款记录保存到数据中时hibernate报异常了,平时设计代码时应将耗时的网络请求操作从事务中剥离,可考虑采用异步的方式执行这些耗时操作,例如消息队列。
1、http://hc.apache.org/httpclient-3.x/performance.html
2、http://hc.apache.org/httpclient-3.x/preference-api.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 编写一个IDEA插件之:使用PSI分析Java代码
- 编写一个IDEA插件之:自动生成Java代码
- 编写一个IDEA插件之:事件监听
- 重新加载故障节点上的 Ceph 卷
- 一个Spring Bean从诞生到逝去的九次人生转折!
- 原创 | 详解git rebase,让你走上git大神之路
- 启用chrome浏览器内置的二维码生成插件
- ZeroLogon漏洞(CVE-2020-1472)防御性指南
- 原创 | 随机数大家都会用,但是你知道生成随机数的算法吗?
- 原创 | codeforces 1425E,一万种情况的简单题
- 原创 | codeforces 1417C,逆向思考的数据结构题
- 原创 | 操作失误不要慌,这个命令给你的Git一次反悔的机会
- 原创 | 想做推荐算法?先把FM模型搞懂再说
- 活见鬼,明明删除了数据,空间却没减少!
- 原创 | Git仓库的提交记录乱成一团,怎么办?