HttpClient优化指南

简介

默认情况下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指南。

猜你喜欢

转载自paleolake.iteye.com/blog/1601322
今日推荐