强制与Java HttpClient立即建立不安全的HTTP2连接

时间:2018-09-26 09:06:52

标签: java http2

仅使用标准Java库作为客户端,如何不安全 HTTP / 2连接在事先知道将使用该协议版本的情况下 ?即无需先通过HTTP / 1.1发送升级请求。

我尝试使用java.net.http中的实用程序,在请求和客户端构建器上调用version(HttpClient.Version.HTTP_2),但是初始请求始终通过HTTP / 1.1发送,带有升级头。到目前为止,从一开始就强制使用版本2的唯一方法似乎是在https上使用安全连接(我想避免这种情况)。

我也想坚持只使用OpenJDK 11中包含的类(没有netty之类)。

1 个答案:

答案 0 :(得分:1)

恐怕在Java 11 http客户端API中似乎无法实现。

最相关的内部JDK类是Http2Connection.java。它列出了我们期望用于HTTP / 2连接的三种“创建”情况:

  1. 升级了HTTP / 1.1纯TCP连接
  2. 先验知识直接创建普通的tcp连接
  3. 直接创建使用ALPN的HTTP / 2 SSL连接。

我们对第2种情况感兴趣。有相关代码:

/**
 * Cases 2) 3)
 *
 * request is request to be sent.
 */
private Http2Connection(HttpRequestImpl request,
                        Http2ClientImpl h2client,
                        HttpConnection connection)
    throws IOException
{
    ...
}

A,此构造函数实际上仅用于安全连接的方法中:

// Requires TLS handshake. So, is really async
static CompletableFuture<Http2Connection> createAsync(HttpRequestImpl request,
                                                      Http2ClientImpl h2client,
                                                      Exchange<?> exchange) {
    assert request.secure();
    AbstractAsyncSSLConnection connection = (AbstractAsyncSSLConnection)
    ...
    return connection.connectAsync(exchange)
              .thenCompose(unused -> connection.finishConnect())
              .thenCompose(unused -> checkSSLConfig(connection))
              .thenCompose(notused-> {
                  CompletableFuture<Http2Connection> cf = new MinimalFuture<>();
                  try {
                      Http2Connection hc = new Http2Connection(request, h2client, connection);
                      cf.complete(hc);
                  } catch (IOException e) {
                      cf.completeExceptionally(e);
                  }
                  return cf; } );

似乎只有在升级HTTP 1.1连接时才会调用非TLS构造函数。

我也研究了许多其他课程。我看不到有任何建议可以在不从JDK 11客户端中从HTTP 1.1升级的情况下就协商明文HTTP / 2连接的事情。

我找到的内容与HttpClient.Builder的javadocs中的API描述非常匹配,后者仅说明了选择HTTP / 2作为版本:

  

如果设置为HTTP / 2,则每个请求都将尝试升级到HTTP / 2。   如果升级成功,则将使用对此请求的响应   HTTP / 2以及所有后续请求和对同一来源的响应   服务器将使用HTTP / 2。如果升级失败,则响应将   使用HTTP / 1.1进行处理

HTTP / 2连接重用中发生了很多有趣的事情。例如,在升级并发请求的情况下,仅保留一个以备将来在HTTP / 2连接“缓存”中使用。当流的数量达到最大值(〜2 ^ 31-1)时,缓存的连接将过期,以使其他请求不会超过它,但是现有的流将保持打开状态。有很多流。我认为,如果您的用例像我的情况(运行时间很长的应用程序中的Web服务客户端)那样,那么实际上仅第一个请求的升级成本就可以忽略不计。我仍然想消除它,主要是为了简单起见,但是我开始认为这是不值得的。

就像质问者一样,我想坚持使用JDK客户端。我只会提到Apache HttpClient 5 beta似乎支持强制HTTP / 2(HttpVersionPolicy.FORCE_HTTP_2)。我对此没有任何进一步的建议,因为该Beta版没有太多的文档,而且注释远比JDK实现稀疏。但是,如果我尝试并获得成功,我将更新我的答案。