网易首页 > 网易号 > 正文 申请入驻

netty系列之:搭建客户端使用http1.1的方式连接http2服务器

0
分享至

简介

对于http2协议来说,它的底层跟http1.1是完全不同的,但是为了兼容http1.1协议,http2提供了一个从http1.1升级到http2的方式,这个方式叫做cleartext upgrade,也可以简称为h2c。

在netty中,http2的数据对应的是各种http2Frame对象,而http1的数据对应的是HttpRequest和HttpHeaders。一般来说要想从客户端发送http2消息给支持http2的服务器,那么需要发送这些http2Frame的对象,那么可不可以像http1.1这样发送HttpRequest对象呢?

今天的文章将会给大家揭秘。

使用http1.1的方式处理http2

netty当然考虑到了客户的这种需求,所以提供了两个对应的类,分别是:InboundHttp2ToHttpAdapter和HttpToHttp2ConnectionHandler。

他们是一对方法,其中InboundHttp2ToHttpAdapter将接收到的HTTP/2 frames 转换成为HTTP/1.x objects,而HttpToHttp2ConnectionHandler则是相反的将HTTP/1.x objects转换成为HTTP/2 frames。这样我们在程序中只需要处理http1的对象即可。

他们的底层实际上调用了HttpConversionUtil类中的转换方法,将HTTP2对象和HTTP1对象进行转换。

处理TLS连接

和服务器一样,客户端的连接也需要区分是TLS还是clear text,TLS简单点,只需要处理HTTP2数据即可,clear text复杂点,需要考虑http升级的情况。

先看下TLS的连接处理。

首先是创建SslContext,客户端的创建和服务器端的创建没什么两样,这里要注意的是SslContextBuilder调用的是forClient()方法:

SslProvider provider =
SslProvider.isAlpnSupported(SslProvider.OPENSSL)? SslProvider.OPENSSL : SslProvider.JDK;
sslCtx = SslContextBuilder.forClient()
.sslProvider(provider)
.ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
// 因为我们的证书是自生成的,所以需要信任放行
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.applicationProtocolConfig(new ApplicationProtocolConfig(
Protocol.ALPN,
SelectorFailureBehavior.NO_ADVERTISE,
SelectedListenerFailureBehavior.ACCEPT,
ApplicationProtocolNames.HTTP_2,
ApplicationProtocolNames.HTTP_1_1))
.build();

然后将sslCtx的newHandler方法传入到pipeline中:

pipeline.addLast(sslCtx.newHandler(ch.alloc(), CustHttp2Client.HOST, CustHttp2Client.PORT));

最后加入ApplicationProtocolNegotiationHandler,用于TLS扩展协议的协商:

pipeline.addLast(new ApplicationProtocolNegotiationHandler("") {
@Override
protected void configurePipeline(ChannelHandlerContext ctx, String protocol) {
if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {
ChannelPipeline p = ctx.pipeline();
p.addLast(connectionHandler);
p.addLast(settingsHandler, responseHandler);
return;
ctx.close();
throw new IllegalStateException("未知协议: " + protocol);

如果是HTTP2协议,则需要向pipline中加入三个handler,分别是connectionHandler,settingsHandler和responseHandler。

connectionHandler用于处理客户端和服务器端的连接,这里使用HttpToHttp2ConnectionHandlerBuilder来构建一个上一节提到的HttpToHttp2ConnectionHandler,用来将http1.1对象转换成为http2对象。

Http2Connection connection = new DefaultHttp2Connection(false);
connectionHandler = new HttpToHttp2ConnectionHandlerBuilder()
.frameListener(new DelegatingDecompressorFrameListener(
connection,
new InboundHttp2ToHttpAdapterBuilder(connection)
.maxContentLength(maxContentLength)
.propagateSettings(true)
.build()))
.frameLogger(logger)
.connection(connection)
.build();

但是连接其实是双向的,HttpToHttp2ConnectionHandler是将http1.1转换成为http2,它实际上是一个outbound处理器,我们还需要一个inbound处理器,用来将接收到的http2对象转换成为http1.1对象,这里通过添加framelistener来实现。

frameListener传入一个DelegatingDecompressorFrameListener,其内部又传入了前一节介绍的InboundHttp2ToHttpAdapterBuilder用来对http2对象进行转换。

settingsHandler用来处理Http2Settings inbound消息,responseHandler用来处理FullHttpResponse inbound消息。

这两个是自定义的handler类。

处理h2c消息

从上面的代码可以看出,我们在TLS的ProtocolNegotiation中只处理了HTTP2协议,如果是HTTP1协议,直接会报错。如果是HTTP1协议,则可以通过clear text upgrade来实现,也就是h2c协议。

我们看下h2c需要添加的handler:

private void configureClearText(SocketChannel ch) {
HttpClientCodec sourceCodec = new HttpClientCodec();
Http2ClientUpgradeCodec upgradeCodec = new Http2ClientUpgradeCodec(connectionHandler);
HttpClientUpgradeHandler upgradeHandler = new HttpClientUpgradeHandler(sourceCodec, upgradeCodec, 65536);

ch.pipeline().addLast(sourceCodec,
upgradeHandler,
new CustUpgradeRequestHandler(this),
new UserEventLogger());
}

首先添加的是HttpClientCodec作为source编码handler,然后添加HttpClientUpgradeHandler作为upgrade handler。最后添加自定义的CustUpgradeRequestHandler和事件记录器UserEventLogger。

自定义的CustUpgradeRequestHandler负责在channelActive的时候,创建upgradeRequest并发送到channel中。

因为upgradeCodec中已经包含了处理http2连接的connectionHandler,所以还需要手动添加settingsHandler和responseHandler。

ctx.pipeline().addLast(custHttp2ClientInitializer.settingsHandler(), custHttp2ClientInitializer.responseHandler());
发送消息

handler配置好了之后,我们就可以直接以http1的方式来发送http2消息了。

首先发送一个get请求:

// 创建一个get请求
FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, GETURL, Unpooled.EMPTY_BUFFER);
request.headers().add(HttpHeaderNames.HOST, hostName);
request.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), scheme.name());
request.headers().add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP);
request.headers().add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.DEFLATE);
responseHandler.put(streamId, channel.write(request), channel.newPromise());

然后是一个post请求:

// 创建一个post请求
FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, POST, POSTURL,
wrappedBuffer(POSTDATA.getBytes(CharsetUtil.UTF_8)));
request.headers().add(HttpHeaderNames.HOST, hostName);
request.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), scheme.name());
request.headers().add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP);
request.headers().add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.DEFLATE);
responseHandler.put(streamId, channel.write(request), channel.newPromise());

和普通的http1请求没太大区别。

总结

通过使用InboundHttp2ToHttpAdapter和HttpToHttp2ConnectionHandler可以方便的使用http1的方法来发送http2的消息,非常方便。

本文的例子可以参考:learn-netty4

本文已收录于 http://www.flydean.com/30-netty-http2client-md/

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
赵今麦,每个男人都想拥有的女孩样板。

赵今麦,每个男人都想拥有的女孩样板。

野狐馋师
2026-02-17 08:50:46
51岁刘恺威近况曝光!与杨幂离婚已7年,与李晓峰分手后事业遇挫

51岁刘恺威近况曝光!与杨幂离婚已7年,与李晓峰分手后事业遇挫

代军哥哥谈娱乐
2026-04-09 10:00:09
宋宁峰炸裂聊天记录曝光,张婉婷卑微挽留丈夫,宋宁峰发长文回应

宋宁峰炸裂聊天记录曝光,张婉婷卑微挽留丈夫,宋宁峰发长文回应

陈意小可爱
2026-04-09 13:40:40
厉害了!郑丽文参访美团,惊叫连连,这波行程安排,太懂人心

厉害了!郑丽文参访美团,惊叫连连,这波行程安排,太懂人心

魔都姐姐杂谈
2026-04-08 22:44:10
一场晚宴改变岛内风向,郑丽文勇敢表态获欣赏,萧旭岑被集体心疼

一场晚宴改变岛内风向,郑丽文勇敢表态获欣赏,萧旭岑被集体心疼

阅微札记
2026-04-09 10:16:11
武汉凌晨下起大冰雹!网友:“睡不着睡不着”

武汉凌晨下起大冰雹!网友:“睡不着睡不着”

极目新闻
2026-04-09 08:50:32
比被新能源车淘汰更可怕的是:油车车主,或将面临这3个难题

比被新能源车淘汰更可怕的是:油车车主,或将面临这3个难题

小熊侃史
2026-04-08 09:53:12
台北市长满意度近七成,国民党支持率却跌破三成。

台北市长满意度近七成,国民党支持率却跌破三成。

吃货的分享
2026-04-09 17:48:49
俄媒这句话直接封神,"只有把中国惹急了,世界才会安静"

俄媒这句话直接封神,"只有把中国惹急了,世界才会安静"

长星寄明月
2026-04-09 15:58:44
意外!中超第5轮 北京国安 成都蓉城 申花 海港比赛都有CCTV直播

意外!中超第5轮 北京国安 成都蓉城 申花 海港比赛都有CCTV直播

80后体育大蜀黍
2026-04-09 18:33:39
西方媒体:哪怕中国全力以赴,也不可能按时建成这样庞大的工程

西方媒体:哪怕中国全力以赴,也不可能按时建成这样庞大的工程

混沌录
2026-04-09 18:45:25
深圳老板破产6年,女儿从国外来电:你忘了伦敦金融街的房子吗?

深圳老板破产6年,女儿从国外来电:你忘了伦敦金融街的房子吗?

农村情感故事
2026-04-06 08:25:36
全国多地“老牌高速公路”收费期限届满,陆续进入“免费通行时代”

全国多地“老牌高速公路”收费期限届满,陆续进入“免费通行时代”

中国能源网
2026-04-08 11:05:04
网友吐槽南航11万里程兑换的护肤品质地与正品差异显著,南航回应:资格认证商家符合条件即可入驻,平台无法保证认证商家商品真伪

网友吐槽南航11万里程兑换的护肤品质地与正品差异显著,南航回应:资格认证商家符合条件即可入驻,平台无法保证认证商家商品真伪

潇湘晨报
2026-04-09 16:16:34
明天将有大事发生  上还是下

明天将有大事发生 上还是下

趋势巡航
2026-04-09 14:49:29
没想到当年咬牙给父母补缴的社保,成了他们晚年最大的底气和体面

没想到当年咬牙给父母补缴的社保,成了他们晚年最大的底气和体面

小马达情感故事
2026-04-08 18:50:07
就业卷到极限,12人花30万买高铁工作,月薪才两千,还是劳务派遣

就业卷到极限,12人花30万买高铁工作,月薪才两千,还是劳务派遣

眼光很亮
2026-04-09 16:15:14
涉黄“翻车”的海河乳品:老字号拼出圈,经销商成“漏洞”

涉黄“翻车”的海河乳品:老字号拼出圈,经销商成“漏洞”

新京报
2026-04-08 23:27:14
加州长纽森心碎点名特朗普马斯克,批对华最大错

加州长纽森心碎点名特朗普马斯克,批对华最大错

吕彏极限手工
2026-04-09 17:08:10
乌克兰数百枚远程导弹虎视眈眈,俄罗斯被迫停止胜利日阅兵彩排

乌克兰数百枚远程导弹虎视眈眈,俄罗斯被迫停止胜利日阅兵彩排

史政先锋
2026-04-09 16:23:18
2026-04-09 19:19:00
flydean程序那些事
flydean程序那些事
最通俗的解读,最深刻的干货!
356文章数 438关注度
往期回顾 全部

科技要闻

Meta凌晨首发闭源大模型 扎克伯格又行了?

头条要闻

一群人闯进女子刚买的新房砸了两面墙 物业称出于好心

头条要闻

一群人闯进女子刚买的新房砸了两面墙 物业称出于好心

体育要闻

8万人面前心脏骤停 现在他还站在球场上

娱乐要闻

金莎官宣结婚 与老公孙丞潇相差18岁

财经要闻

停火首日,霍尔木兹仅有4艘船通过

汽车要闻

文飞的回归 给神行者带来什么?

态度原创

艺术
本地
教育
手机
公开课

艺术要闻

庞茂琨 2026油画写生新作

本地新闻

12吨巧克力有难,全网化身超级侦探添乱

教育要闻

被严重低估!全市唯一有招生代码的公办高中国际部

手机要闻

Find X9 Ultra影像实力揭晓 打造专业口袋哈苏

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版