通过 JAX-RS 客户端支持 HTTP/1.1 和 HTTP/2

Posted

技术标签:

【中文标题】通过 JAX-RS 客户端支持 HTTP/1.1 和 HTTP/2【英文标题】:Support HTTP/1.1 and HTTP/2 with a JAX-RS client 【发布时间】:2017-07-09 22:30:17 【问题描述】:

我想为 JAX-RS 客户端实现一个支持 HTTP/1.1 和 HTTP/2 的 JAX-RS 客户端。

如果服务器支持带有 HTTP/2 的 ALPN,则使用 HTTP/2,如果服务器不提供任何信息,则使用 HTTP/1.1。

我已经阅读了一些关于 ALPN 的文章,这似乎是可能的,但我没有找到任何同时支持这些协议的东西。我没有设法将它们连接在一起。

我目前正在使用Jetty HTTP/1.1 transport connector for Jersey 和custom implementation for HTTP/2 transport connector。

【问题讨论】:

您希望 open an issue 到 Jetty 以支持基于 ALPN 动态选择要使用的传输。这样,您将只编写一个适用于这两种协议的 Jersey 传输。谢谢! @sbordet 我刚刚创建了issue 您是否尝试在您的应用程序中使用任何异步调用 @SaurabhJhunjhunwala 暂时同步 【参考方案1】:

解决方案可能是使用 nginx(或 apache2)作为反向代理来处理该要求。

Nginx 可以将您的码头服务器(仅使用 http/1.1 或 http/2 协议)和带有 alpn 的服务器 http/2(使用最新版本)代理到客户端。

【讨论】:

确实可以解决。但是有几个缺点,即您需要破坏反向代理中的 TLS 加密,您必须更改服务器,而它可能是外部方,并且您必须在客户端中选择一种协议,而问题的重点是支持两种协议的客户端。【参考方案2】:

事实上,ALPN 仅由 jdk 从 JDK9 开始支持 http://unrestful.io/2015/10/09/alpn-java.html.

这不是由 JAX-RS 客户端 api 处理的

【讨论】:

可以使用带有 JVM TLS 客户端的库(Jetty ALPN)或使用另一个 TLS 客户端(例如 conscrypt)来支持它。如果底层传输处理它,它可以通过 JAX-RS 处理。目前除了 Jetty 项目之外没有其他人想要实现它github.com/eclipse/jetty.project/issues/1350。 好的,但是要实现 JAX-RS,您使用现有的 http 客户端实现,我想 Jetty 的 HttpClient 会为您处理 ANPL? 我使用 JAX-RS 的 Jersey 实现,它在 Java HttpUrlConnectionHTTP1 客户端的底层使用。 Jetty HTTP/1.1 客户端也可以配置。我还写了一个HTTP/2 client based on Jetty。但是,没有使用 ALPN 支持 HTTP/1.1 和 HTTP/2 的底层传输。【参考方案3】:

如果这个问题仍然可以贡献,那么有一种方法可以用

如您所知,如果使用 TLSv1.2 (h2),HTTP/2 需要 ALPN 支持。

netty 包对 HTTP/2 有一些支持,前提是您在平台上安装了 openssl(版本 1.0.2 或更高版本)。

Netty 包将通过调用本地库使用 OpenSSL 来支持 ALPN。

我们使用 JDK8 实现了一个客户端,并设法生成 http2 请求以供服务器仅接受 http2 请求的操作。我们使用了下面提到的依赖项

    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <!--<version>5.0.0.Alpha2</version> -->
        <version>4.1.29.Final</version>
    </dependency>

【讨论】:

其实我正在寻找一个能够同时做到这两个的客户端,我不认为你的客户端在做 HTTP/1 和 HTTP/2 吗? 我的客户端同时使用 HTTP/1.1 和 HTTP/2。默认情况下,它使用 HTTP/1.1 & 对于只接受 HTTP/2 的特定服务,我们创建 HTTP/2 请求 能否从ALPN输出中动态选择协议? 应用程序已经知道仅支持 HTTP/2 的特定服务,如果正在调用此服务,那么我们构建 ssl 上下文和 HTTP/2 所需的请求。 好的,我已经完成了这项工作(我有一个单独的 HTTP/1 和 HTTP/2 客户端,请参阅问题中的链接)但不是动态的,这实际上是我的问题。【参考方案4】:

这听起来像你的问题,抽象地说,你是否想要一个 Java servlet,而不是可以协商 终止单个 REST 端点,因此避免一个用于 HTTP/1 的接口和另一个用于 HTTP/2 的接口,并避免外部终止,例如通过可以处理多个协议的代理。所以是一个多合一的 servlet。

至少在 2017 年 Steve Hu 添加测试用例和 PR 时,Stuart(和 JBoss 人员)已经在 Undertow 中实现了这一点。 1

您需要在 OptionsMap 中传入 ENABLE_HTTP2 选项。为了 http URI's 这意味着客户端将尝试在 第一个请求,对于 https URI 的 ALPN 将用于尝试和协商 HTTP/2。这就是浏览器的行为方式,即使目标 不支持 HTTP/2。 2

看起来 Simone 正在推动更改以在 Jetty 中实现这一点。 3 所以如果你现在想要这个,从 Jetty 切换到 Undertow,或者将问题更改为“Support ... in Jetty”。

【讨论】:

这看起来很有希望,但实际上我到目前为止还没有找到一种方法来集成 JAX-RS 和支持 HTTP/1 和 HTTP/2 的 HTTP 客户端,具体取决于目标服务器。据我所知,没有带有 JAX-RS 实现的 Undertown 客户端连接器? Simone 的实现与我在 Jetty 中创建的问题有关。但是,如果有另一个连接器能够连接 HTTP/1 和 HTTP/2,我可以切换 ;-) Undertow 已经集成为 Wildfly 的 servlet,Wildfly 具有 JAX-RS,它被实现为 RESTEasy b/c ......好吧,它是一个 JBoss 项目而不是 Apache 项目,但你可以同时获得两者。我也很想在上面尝试你的场景以验证它是否有效,那么你有一个公开的测试用例吗? 其实我不想要 Servlet 实现,而是 HTTP JAX-RS 客户端实现端,除非我错过了什么,否则 Undertown 似乎不会实现它? 啊,那我误会了。【参考方案5】:

Java 11 提供的 Java HTTP 客户端支持 HTTP/1.1 和 HTTP/2(请参阅 Introduction to the Java HTTP Client)。

我已经使用它构建了一个连接器Jersey Connector using java.net.http.HttpClient。 您可以使用它添加以下依赖项。

<dependency>
  <groupId>com.github.nhenneaux.jersey.connector.httpclient</groupId>
  <artifactId>jersey-httpclient-connector</artifactId>
  <version>0.2.2</version>
</dependency>

【讨论】:

太棒了!谢谢你。问题仍然是为什么这不是泽西岛的默认设置。

以上是关于通过 JAX-RS 客户端支持 HTTP/1.1 和 HTTP/2的主要内容,如果未能解决你的问题,请参考以下文章

JAX-RS(基于Jersey) + Spring 4.x + MyBatis构建REST服务架构

http2概述及Java9对其的支持

如何正确中断 JAX-RS AJAX 请求

使用 JAX-RS/RESTEasy 实现 CORS 的 Ajax 请求

不支持HTTP / 1.1 505 HTTP版本:处理(客户端)到Heroku应用服务器

如何在 JAX-RS API 中添加超时