简介
默认情况下HttpClient配置为了提供最大的可靠性和标准遵从性而非性能。有多个配置选项和优化技术能够显著提高HttpClient的性能。此指南列出了实现HttpClient的性能最大化的各种技术。
内容
- 重用HttpClient实例
- 连接持久性
- 并发执行HTTP方法
- 请求/响应实体流
- 期望继续握手
- 陈旧连接检查
- Cookie处理
重用HttpClient实例
一般,推荐的做法每个通信组件或甚至每个应用程序都只有一个HttpClinet的实例,如果应用程序很少使用HttpClient,在内存中保持闲置HttpClient实例是不恰当的,我们极力建议您显式关闭多线程连接管理器的之前先释放HttpClient的实例,这将确保正确地关闭HTTP连接池中的所有连接。
连接持久性
HttpClient重复使用连接是好的做法。连接持久性默认就开启了,并不需要特别的配置,但是在某些情况下这可能会导致泄露,因此失去了资源的连接。最简单方法就是禁用连接持久性,提供或扩展一个在连接管理器,并在其releaseConnection方法中强制关闭释放连接。
并发执行HTTP方法
如果应用程序逻辑允许并发执行多个HTTP请求(也就是说,针对不同站点的多个请求,或是代表不同的用户身份的多个请求),每个HTTP会话中使用一个专门的线程可能会产生重大的性能提升。当使用一个线程安全的连接管理器(如MultiThreadedHttpConnectionManage)时,HttpClient完全线程安全的。请注意,每个执行的线程都必须具有它自己的HttpMethod类的实例,并且可以具有HttpState或(和) 表示一个特定的主机配置HostConfiguration本地实例和会话状态。同时,为了最大效率,HttpClient实例和连接管理器在所有的线程中共享。 HttpClient的使用多个线程的详细信息,请参阅HttpClient线程指南。
请求/响应实体流
HttpClient具有高效处理请求/响应正文流的能力。大型实体可能在内存中设置缓存下提交或接收。如果同时执行多个HTTP方法,这尤其重要。虽然有便利的方法来处理实体,诸如字符串或字节数组,但是都不是最好的处理方法。除非小心地使用,它们很容易导致内存不足的情况,因为它们暗示着内存中的缓冲完整实体。 响应流:建议使用 HttpMethod#getResponseBodyAsStream的方法把HTTP响应内容作为字节/字符流来处理。强烈不建议使用HttpMethod#getResponseBody 和 HttpMethod#getResponseBodyAsString。
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("http://www.myhost.com/");
try {
httpclient.executeMethod(httpget);
Reader reader = new InputStreamReader(
httpget.getResponseBodyAsStream(), httpget.getResponseCharSet());
// consume the response entity
} finally {
httpget.releaseConnection();
}
请求流:遇到的主要的困难是实体流包装的一些方法在认证失败或者是IO失败需要重试。显然,非缓冲实体无法重新读取和重新提交。建议的方法是创建一个能够重建基础的输入流自定义请求实体(RequestEntity)。
public class FileRequestEntity implements RequestEntity {
private File file = null;
public FileRequestEntity(File file) {
super();
this.file = file;
}
public boolean isRepeatable() {
return true;
}
public String getContentType() {
return "text/plain; charset=UTF-8";
}
public void writeRequest(OutputStream out) throws IOException {
InputStream in = new FileInputStream(this.file);
try {
int l;
byte[] buffer = new byte[1024];
while ((l = in.read(buffer)) != -1) {
out.write(buffer, 0, l);
}
} finally {
in.close();
}
}
public long getContentLength() {
return file.length();
}
}
File myfile = new File("myfile.txt");
PostMethod httppost = new PostMethod("/stuff");
httppost.setRequestEntity(new FileRequestEntity(myfile));
期待继续握手
HTTP 100的状态的目的就是,在客户端发送请求实体前,允许客户端发送一个请求实体去确认目标服务器将是否接受此请求(基于请求头)。如果服务器拒绝了此次请求而没有去查看请求正文,那么对于客户端来说是非常低效率的。基于请求头的请求被拒绝的最常见的原因就是身份验证失败。因此,'期望继续'握手的用法是特别推荐这些需要HTTP身份验证的目标服务器。 从事旧HTTP1.0代理服务器必须慎重对待,因为可能无法正确处理'期望继续'握手。 更多的信息http.protocol.expect-continue 参数文档。
陈旧的连接检查
HTTP规范允许客户端和服务器随时终止持续(keep-alive)连接而无须通知对方的,这就会让连接无效或 陈旧。默认情况下,在执行请求之前,HttpClient执行检查去确认连接是否已陈旧,这个操作耗时15-30毫秒,依赖于使用的JRE(JDK)。禁用陈旧的连接的检查可能会有轻微的性能提升,尤其是对小有效载荷的响应,但是在执行一个服务端已关闭的连接时将冒着IO错误的风险。
Cookie处理
如果一个应用程序,像网络爬虫,不需要维护与目标服务器的会话状态,禁用Cookie处理能够获取小的性能提升。关于Cookie处理详细的信息,请参考HttpClient Cookie指南。