使用JAX-RS客户端支持HTTP/1.1和HTTP/2

24

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

如果服务器支持ALPN协议,就使用HTTP/2,如果服务器没有提供任何信息,则使用HTTP/1.1。

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

我目前正在使用Jersey的Jetty HTTP/1.1传输连接器自定义的HTTP/2传输连接器实现


4
您希望在Jetty上开一个问题,支持基于ALPN动态选择要使用的传输协议。这样,您只需要编写一个适用于两种协议的Jersey传输协议。谢谢! - sbordet
2
@sbordet 我刚刚创建了这个问题 - Nicolas Henneaux
你的应用程序中是否尝试使用任何异步调用? - Saurabh Jhunjhunwala
@SaurabhJhunjhunwala 目前只是进行同步。 - Nicolas Henneaux
5个回答

4

Java 11提供的Java HTTP客户端支持HTTP/1.1和HTTP/2(请参见Java HTTP客户端介绍)。

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

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

Maven Central


1
太棒了!谢谢。问题仍然是为什么这不是Jersey的默认设置。 - Hank

-1

可以使用JVM的TLS客户端库(Jetty ALPN)或其他TLS客户端(例如conscrypt)来支持它。如果底层传输处理它,则可以通过JAX-RS处理它。目前还没有,但Jetty项目希望实现它https://github.com/eclipse/jetty.project/issues/1350。 - Nicolas Henneaux
好的,但要实现JAX-RS,您需要使用现有的HTTP客户端实现,我想是Jetty的HttpClient,它会为您处理ANPL吗? - Mr_Thorynque
我使用JAX-RS的Jersey实现,它在底层使用Java HttpUrlConnection HTTP1客户端。Jetty HTTP/1.1客户端也可以进行配置。我还编写了一个基于Jetty的HTTP/2客户端。然而,没有底层传输支持使用ALPN的HTTP/1.1和HTTP/2。 - Nicolas Henneaux

-2

从抽象的角度来看,您的问题似乎是想要一个Java servlet,可以协商并终止单个REST端点,从而避免为HTTP/1和HTTP/2分别提供接口,并避免外部终止,例如通过可以处理多种协议的代理。因此需要一个全能的servlet。

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

您需要在OptionsMap中传递ENABLE_HTTP2选项。对于http URI,这意味着客户端将尝试在第一次请求时进行升级,对于https URI,ALPN将被用于尝试协商HTTP/2。这就是浏览器的行为方式,即使目标不支持HTTP/2也可以工作。2

看起来Simone正在推动更改以在Jetty中实现这一点。 3 因此,如果您现在想要这个功能,请从Jetty切换到Undertow,或将问题更改为“在Jetty中支持...”。


这似乎很有前途,但实际上我迄今为止还没有找到一种集成JAX-RS和支持HTTP/1和HTTP/2的HTTP客户端的方法,具体取决于目标服务器。据我所知,没有一个Undertown客户端连接器与JAX-RS实现相关联?Simone的实现与我在Jetty中创建的问题有关。然而,如果有另一个连接器能够连接HTTP/1和HTTP/2,我可以切换;-) - Nicolas Henneaux
Undertow已经作为Wildfly的servlet集成,而Wildfly具有JAX-RS,它是作为RESTEasy实现的,因为...嗯,它是一个JBoss项目而不是Apache项目,但你可以得到两者。我也很想尝试一下您的方案以验证其是否有效,所以您是否有公共测试用例? - Justin
实际上,我不需要Servlet实现,而是HTTP JAX-RS客户端实现方面的内容,但似乎Undertown没有实现,除非我漏掉了什么? - Nicolas Henneaux
啊,那我误解了。 - Justin

-2
一个解决方案是使用nginx(或apache2)作为反向代理来处理该要求。
Nginx可以代理您的jetty服务器(仅使用http/1.1或http/2协议),并使用最新版本的alpn向客户端提供http/2服务。

确实这可能是一个解决方案。然而,有几个缺点,比如你需要在反向代理中打破TLS加密,你必须更改服务器,而它可能是外部方,并且你必须为你的客户端选择一个协议,而问题的重点是拥有一个支持两种协议的客户端。 - Nicolas Henneaux

-2
如果这个问题仍然可以贡献,那么有一种实现客户端与JDK 9版本以下的方法。
如您所知,HTTP/2需要ALPN支持,如果使用TLSv1.2(h2)。 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的客户端,我不认为你的客户端支持这两种协议吧? - Nicolas Henneaux
我的客户同时使用HTTP/1.1和HTTP/2。默认情况下,它使用HTTP/1.1,对于仅接受HTTP/2的特定服务,我们创建HTTP/2请求。 - Ashish Patil
它能否从ALPN输出动态选择协议? - Nicolas Henneaux
应用程序已经知道特定服务仅支持HTTP/2,如果正在调用此服务,则我们将构建SSL上下文和所需的HTTP/2请求。 - Ashish Patil
好的,我已经让它工作了(我有一个针对HTTP/1和HTTP/2的单独客户端,请参见问题中的链接),但实际上我的问题是动态的。 - Nicolas Henneaux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接