Apache HttpClient 4.5 长连接池及 Fluent API 介绍

时间:2025-05-13 14:52:49

Apache HttpClient 4.5 长连接池及 Fluent API 介绍

最近的项目中用到了 Apache HttpComponents 项目中 HttpClient 4.5 长连接池的功能,再研究官方标准写法的同时,突然看到了Apache HttpClient Fluent API,相比之前 HttpClient 的传统书写方式,Fluent API 方便了很多。

在介绍之前先准备一下实例代码中用到的工具类,工具类中添加了 HttpClient 连接的创建方法和构建表单方式的 Http 实体内容的方法:

package ;

import ;
import ;
import ;
import ;
import ;
import ;
import ;

import ;
import ;
import ;
import ;
import ;
import ;

/**
 * Http 连接池帮助类
 *
 * @author 
 * @see 
 * @see 
 */
public class HttpPoolHelper {

    public static CloseableHttpClient buildPoolHttpClient(int liveSeconds, int maxPerRoute, int maxTotal) {
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(liveSeconds, );
        (2_000);// 每隔 2 秒才检查连接的有效性
        (maxPerRoute);// 默认最大预处理路由,如果只有一个路由,可以等于 maxTotal
        (maxTotal);//连接池最大值
        return ().setConnectionManager(cm).build();
    }

    public static UrlEncodedFormEntity buildFormEntity(Map<String, String> params) {
        return new UrlEncodedFormEntity(paramToPair(params), StandardCharsets.UTF_8);
    }

    /**
     * @see 
     */
    public static List<NameValuePair> paramToPair(Map<String, String> params) {
        List<NameValuePair> result = ();
        if ((params)) {
            result = new ArrayList<>(());
            for (<String, String> entry : ()) {
                String value = ();
                if (value != null) {
                    String key = ();
                    (new BasicNameValuePair(key, value));
                }
            }
        }
        return result;
    }

}

如果没有 HTTP 代理、自定义 HTTP 头、自定义 HTTP Cookies、HTTP 访问验证这些东西的话,HttpClient 的长连接的实现是非常简便的。HttpClient 的代码普遍使用了类似工厂模式的设计模式,代码可读性不错。下面就讲讲 Fluent API 的用法。

先提供一个没有 Fluent API 的 Http Post 的写法:

    public static String httpPost(String uri, Map<String, String> params, int timeoutMills) throws IOException {
        try (CloseableHttpClient httpclient = ()) {
            HttpPost httpPost = new HttpPost(uri);
            RequestConfig requestConfig = ()
                    .setConnectionRequestTimeout(timeoutMills) // 比 Fluent API 可以多配置一个 timeout
                    .setConnectTimeout(timeoutMills)
                    .setSocketTimeout(timeoutMills)
                    .build();
            (requestConfig);
            ((params));
            try (CloseableHttpResponse response = (httpPost)) {
                return (());
            }
        }
    }

多亏了 Java 1.7 的 try-with-resource 语法,让这段代码可以也可以写得非常短,但里面嵌套了两层的 try 块。
另外来看看 Fluent API 的链式写法:

    public static String fluentPost(String uri, Map<String, String> params, int timeoutMills) throws IOException {
        return (uri) //
                .socketTimeout(timeoutMills) //
                .connectTimeout(timeoutMills) //
                .body((params)) //
                .execute().returnContent().asString(StandardCharsets.UTF_8);
    }

使用 Fluent API 后实际可以一行代码搞定这个 HttpPost 请求。


另外来段非 Fluent API 下 Http 连接池的 POST 写法:

    private static CloseableHttpClient httpClient;

    static {
        httpClient = (600, 100, 100);
    }

    public static String httpPoolPost(String uri, Map<String, String> params, int timeoutMills) throws IOException {
        HttpPost httpPost = new HttpPost(uri);
        RequestConfig requestConfig = ()
                .setConnectTimeout(timeoutMills)
                .setSocketTimeout(timeoutMills)
                .build();
        (requestConfig);
        ((params));
        try (CloseableHttpResponse response = (httpPost)) {
            return (());
        }
    }

Fluent API 下 Http 连接池的POST 写法:

private static Executor executor;

    static {
        executor = (httpClient);
    }

    public static String fluentPoolPost(String uri, Map<String, String> params, int timeoutMills) throws IOException {
        Request body = (uri)
                .socketTimeout(timeoutMills)
                .connectTimeout(timeoutMills)
                .body((params));
        return (body).returnContent().asString(StandardCharsets.UTF_8);
    }

Fluent API 下也是两步搞定,不过这一块跟非连接池下的代码很类似,这也说明了 HttpClient 的封装非常不错。

总结,本文主要是为了备注一下 HttpClient 长连接的写法和 Fluent API 的用途,见解非常微浅,请大家见谅。

还有 Fluent API 跟 Spring RestTemplate API 很相似,在不使用 Http 连接池的情况下,可能 Spring RestTemplate API 更实惠。

write by