写点什么

HttpClient5 升级笔记 --API 篇

作者:FunTester
  • 2023-12-25
    河北
  • 本文字数:4974 字

    阅读完需:约 16 分钟

最近终于是安奈不住升级的冲动,将自己项目的 HttpClient 版本从 4 升级到了 5,其过程不可谓不艰辛,很多 API 改动让人无从下手。


Apache HttpClient 5(也称为 HttpClient 5.x)是 Apache HttpComponents 项目中的一个重要组件,用于发送 HTTP 请求和处理 HTTP 响应。它在与网络通信和处理方面提供了许多优势:


  1. 模块化设计: HttpClient 5 采用了模块化的设计,将核心功能拆分为不同的模块。这种设计使得用户可以根据自己的需求选择性地引入和使用不同的功能模块,从而降低了依赖的复杂性。

  2. 高度可定制: 提供了丰富的配置选项和可定制性,允许开发人员根据特定需求配置连接管理、超时、代理、安全策略等参数。

  3. 异步支持: 提供了对异步请求的支持,可以利用异步方式发送请求并处理响应,有助于提高系统的并发能力和性能。

  4. 优化的连接管理: 引入了更灵活和高效的连接管理机制,包括连接池管理、连接复用,可有效减少连接的建立和关闭次数,提高资源利用率。

  5. HTTP/2 支持: 支持 HTTP/2 协议,允许客户端使用 HTTP/2 进行通信,提高了性能和效率,尤其是在处理大量并行请求时。

  6. 最新的标准和协议支持: 支持最新的 HTTP 标准和协议,包括 HTTP/1.1、HTTP/2、TLS/SSL 等,使得 HttpClient 5 在安全性和性能方面都能够保持更新和竞争力。

  7. 优化的代码结构和性能: 重新设计和优化的代码结构,使得 HttpClient 5 在处理请求和响应时更加高效和可靠。

  8. 易于使用的 API: 提供了简单易用的 API,使得发送 HTTP 请求和处理响应变得更加直观和简单。


针对以上好处,本人仅仅感受到了一点点,但是成本远高于好处,经过简单自测,整体感觉没有质的提升。唯一吸引我的还是 HTTP/2 的支持,不过本地没有开发该协议接口,暂时还没测试,目前主流还是 HTTP 1.1。


这是 FunTester 项目中升级到 HttpClient 5 的依赖版本。


        <dependency>            <groupId>org.apache.httpcomponents.client5</groupId>            <artifactId>httpclient5</artifactId>            <version>5.3</version>        </dependency>
复制代码


其中依赖版本不变,如果你项目里面其他库依赖了 HttpClient 4.x 版本,记得排除掉,避免干扰。


下面开始分享 API 改动点,内容不分先后,按照我 FunTester 项目从上至下列举。以下问容中旧版本指的是 4.x,新版指的是 5.3。

包名

包名改成了 org.apache.hc.client5. 开头的,需要不少手动工作量。

重试

在旧版本中叫 HttpRequestRetryHandler,新版本叫做 HttpRequestRetryStrategy,中文应该是重测策略。实现方法上也有所不同。旧版本方法 public boolean retryRequest(IOException exception, int executionCount, HttpContext context) ,而新版本需要实现多个方法: public boolean retryRequest(HttpRequest httpRequest, IOException e, int i, HttpContext httpContext)public boolean retryRequest(HttpResponse httpResponse, int i, HttpContext httpContext)public TimeValue getRetryInterval(HttpResponse httpResponse, int i, HttpContext httpContext) 第一个方法跟旧接口很相似,代码直接可以套用。第二个方法用于对响应信息进行判断重试,这个方法挺不错的,很有市场。第三个方法获取重试间隔,由于我并没有设置改功能,所以并没有什么用。但是大家注意引入了新类 org.apache.hc.core5.util.TimeValue ,在 HttpClient 5 中,大量使用这个类作为时间配置。

连接配置

新的版本取消了一批 API,下面是我旧代码:


        ConnectionConfig connectionConfig = ConnectionConfig.custom().setMalformedInputAction(CodingErrorAction.IGNORE).setUnmappableInputAction(CodingErrorAction.IGNORE).setCharset(Constant.DEFAULT_CHARSET).setMessageConstraints(messageConstraints).build();
复制代码


下面是新代码:


ConnectionConfig connectionConfig = ConnectionConfig.custom()// 设置连接配置          .setConnectTimeout(Timeout.of(Duration.ofMillis(CONNECT_TIMEOUT))) // 设置连接超时          .setSocketTimeout(Timeout.of(Duration.ofMillis(SOCKET_TIMEOUT))) // 设置 socket 超时          .setTimeToLive(Timeout.of(Duration.ofMillis(MAX_ACCEPT_TIME))) // 设置生存时间          .setValidateAfterInactivity(Timeout.of(Duration.ofMillis(MAX_ACCEPT_TIME))) // 设置在不活动之后验证          .build();
复制代码


总体讲没有太大差异,后两个配置项对于性能测试来讲也不重要,毕竟连接资源还有连接管理器和异步的资源回收线程负责。

连接池管理器

旧代码:


// 采用绕过验证的方式处理https请求        // 设置协议http和https对应的处理socket链接工厂的对象        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.INSTANCE).register("https", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)).build();        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry, dnsResolver);        // 消息约束        MessageConstraints messageConstraints = MessageConstraints.custom().setMaxHeaderCount(HttpClientConstant.MAX_HEADER_COUNT).setMaxLineLength(HttpClientConstant.MAX_LINE_LENGTH).build();
复制代码


新代码依旧是取消了一些配置 API,其中改动比较大就是创建 API,虽然 PoolingHttpClientConnectionManager 重载构造方法非常多,但是顺序写死了,我只想设置连接配置和 DNS 解析器,如果用构造方法,必须使用一个 N 个参数的,非常不优雅。这里推荐 builder 来完成,我们来看 build()方法源码:


        PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(RegistryBuilder.create().register(URIScheme.HTTP.id, PlainConnectionSocketFactory.getSocketFactory()).register(URIScheme.HTTPS.id, this.sslSocketFactory != null ? this.sslSocketFactory : (this.systemProperties ? SSLConnectionSocketFactory.getSystemSocketFactory() : SSLConnectionSocketFactory.getSocketFactory())).build(), this.poolConcurrencyPolicy, this.poolReusePolicy, (TimeValue)null, this.schemePortResolver, this.dnsResolver, this.connectionFactory);
复制代码


默认是有 HTTP 的连接工厂类注册到连接池管理器中的,所以不用重复设置了,而且也没有预留设置 HTTP 的 API。


异步连接池管理器大差不差,其中有一个 TlsStrategy 是同步管理器没有的,设置方法如下:


.setTlsStrategy(new BasicClientTlsStrategy(sslContext))
复制代码


builder 创建这次新的 API 用了 create()方法,旧的 API 还是使用 custom()。

请求配置

在请求配置中,依然取消了不少 API,主要是跟连接怕这出重复的配置项,比较喜欢这种,同一个配置多处配置会导致额外的问题和排查成本,新代码如下:


private static RequestConfig getRequestConfig() {      return RequestConfig.custom().setConnectionRequestTimeout(Timeout.ofMilliseconds(CONNECT_REQUEST_TIMEOUT)).setCookieSpec("ignoreCookies").setRedirectsEnabled(false).build();  }
复制代码


这里有一个 cookieSpec 的设置比较尴尬,保留了 API,却取消了配置项的枚举类,之后先用字符串代替一下,放迷路内容:


@Deprecated  public static final String BROWSER_COMPATIBILITY = "compatibility";  public static final String NETSCAPE = "netscape";  public static final String STANDARD = "standard";  public static final String STANDARD_STRICT = "standard-strict";  /** @deprecated */  @Deprecated  public static final String BEST_MATCH = "best-match";  public static final String DEFAULT = "default";  public static final String IGNORE_COOKIES = "ignoreCookies";
复制代码


在性能测试当中,不需要 CookieStore 来管理 cookie,所以选择忽略。

创建 HttpClient

我用到了一个新的 API org.apache.hc.client5.http.impl.classic.HttpClientBuilder#disableCookieManagement 看源码文档,看着是取消 CookieStore 的配置,因为我两处都设计了,暂时没有发现异常。

拦截器

方法参数多了一个,旧代码:


            public void process(HttpResponse httpResponse, HttpContext httpContext)
复制代码


新代码:


public void process(HttpResponse httpResponse, EntityDetails entityDetails, HttpContext httpContext)
复制代码

资源回收

连接池管理器有两个可供调用的资源回收方法,通常会异步调用防止资源异常:


connManager.closeExpiredConnections();connManager.closeIdleConnections(HttpClientConstant.IDLE_TIMEOUT, TimeUnit.SECONDS);
复制代码


新代码如下:


connManager.closeExpired();  connManager.closeIdle(TimeValue.ofSeconds(IDLE_TIMEOUT));
复制代码

异步客户端

启动异步客户端的方法 start()不变,但是源码中判断逻辑有些区别,特别是在状态属性上。旧代码:


public void start() {      if (this.status.compareAndSet(CloseableHttpAsyncClientBase.Status.INACTIVE, CloseableHttpAsyncClientBase.Status.ACTIVE) && this.reactorThread != null) {          this.reactorThread.start();      }    }
复制代码


新代码:


public final void start() {      if (this.status.compareAndSet(AbstractHttpAsyncClientBase.Status.READY, AbstractHttpAsyncClientBase.Status.RUNNING)) {          DefaultConnectingIOReactor var10001 = this.ioReactor;          this.executorService.execute(var10001::start);      }    }
复制代码

代理

在旧代码中,代理配置可以直接在 HttpClient 中设置,新代码将 API 设置为过时,需要在 RequestConfig 中设置才行,代码不变,如下:


setProxy(new HttpHost(ip, port))
复制代码

请求、响应对象名称

启用了一大批 classic 开头的对象,例如 org.apache.hc.core5.http.message.BasicClassicHttpRequestorg.apache.hc.core5.http.ClassicHttpResponse ,而且各类封装号的 HTTP 请求对象的报名也变成了 org.apache.hc.client5.http.classic.methods 。看来这个版本要回归经典了。

实体接口

在旧版代码中,想要处理请求或者响应实体,必须是 org.apache.http.HttpEntityEnclosingRequest 对象,在新版代码中变成了 org.apache.hc.core5.http.HttpEntityContainer ,而且取消了 boolean expectContinue() 方法。

全员携带实体

在旧版代码中,GET 和 DELETE 请求默认是不携带请求实体的,如果想实现该功能需要使用者自己实现,新版中,全员携带实体。这个改变还是很喜闻乐见的。

设置实体

设置实体的 API 也有少许变动,原来是设置 String 类型编码格式,现在直接设置 java.nio.charset.Charset ,真是一大进步。

获取 header

方法名从 getAllHeader 变成了 getHeaders,别的没了。

响应行

HttpClient 5 取消了 获取响应行的的 API getStatusLine ,如果想获取状态码,请用:org.apache.hc.client5.http.impl.classic.CloseableHttpResponse#getCode ,个人感觉并不合适,这跟 HTTP 请求构成有点不一致,但是方便了倒是真的。

获取 URI

旧版方法:getURI,返回 URI 对象,新版:getUri,也返回 URI 对象,还有一个 getRequestUri 返回 String 对象。就是大小写的差异,怀疑是不是为了适配代码自动补充的工具。

异步请求

在同步的 HttpClient 中也是支持异步请求的,旧版代码和同步请求公用请求对象,新版代码增加了新的请求对象:org.apache.hc.client5.http.async.methods.SimpleHttpRequest,这个类明白子类,也不继承于前文提到的 HttpUriRequestBase,感觉就是独立分支一样。同样的响应对象也是 org.apache.hc.client5.http.async.methods.SimpleHttpResponse


HttpClient 5 中两者都提供了从同步对象拷贝的方法copy(),奇怪的是请求的拷贝被标记成了过时方法,迷惑行为。从源码中看到可以方便快捷创建 GET 和 POST 请求。


响应中有直接获取 body 的方法 org.apache.hc.client5.http.async.methods.SimpleHttpResponse#getBodyText,看了一下,不太好借鉴到同步方法中。

总结

一个字:折腾。API 调用已经完活儿了,后期再根据测试结果分享其他方面的变更感受。


如果没有强需求,不建议升级 HttpClient 5。


发布于: 刚刚阅读数: 5
用户头像

FunTester

关注

公众号:FunTester,800篇原创,欢迎关注 2020-10-20 加入

Fun·BUG挖掘机·性能征服者·头顶锅盖·Tester

评论

发布
暂无评论
HttpClient5升级笔记--API篇_FunTester_InfoQ写作社区