当前位置: 首页 > 后端技术 > Java

有这么好的东西!Netty自带http2编解码器framecodec

时间:2023-04-02 09:16:32 Java

介绍Netty为我们提供了很多http2包,让我们可以轻松搭建一个支持http2的服务器。我们唯一需要自定义的是http2处理程序。在上一篇文章中,我们介绍了自定义http2handler继承自Http2ConnectionHandler,实现了Http2FrameListener。这种实现方式目前是netty推荐的。今天给大家介绍的实现方法是替换netty中继承Http2ConnectionHandler的实现方法,但是这个实现方法还不成熟,还在完善中。今天就给大家介绍一下这个实现方法。Http2FrameCodec这个实现的核心类是Http2FrameCodec。实际上Http2FrameCodec也是继承自Http2ConnectionHandler。它的主要功能是映射HTTP/2中的帧和Http2Frame对象。Http2Frame是对netty中所有http2frame对应的封装,这样可以在后续的handler中专注于处理Http2Frame对象,从而摆脱http2协议的各种细节,减少用户的工作量。对于每个传入的HTTP/2帧,Http2FrameCodec将创建一个Http2Frame对象并将其传递给channelRead方法来处理该对象。通过调用write方法,可以将出站的Http2Frame转换为http2帧格式。在Http2Frame、Http2FrameStream和Http2StreamFramenetty中有3个非常相似的类,它们分别是Http2Frame、Http2FrameStream和Http2StreamFrame。我们知道netty中一个tcp连接可以建立多个流,而Http2FrameStream就是流对应的类。此类包含流的ID和流的当前状态。一个stream中包含多条消息,每条消息由多个帧组成,所以Http2Frame就是这些帧对应的netty类。Http2StreamFrame本身也是一个框架,实际上它继承自Http2Frame。为什么会有这个类?因为对应的frame本身一般都与特定的流关联,Http2StreamFrame就代表了这种关联,通过其setstream方法可以指定其关联的流。如果你希望框架应用于整个连接而不是特定的流,如果它与整个连接相关联,那么stream()方法的返回为null。Http2FrameCodec的构造虽然Http2FrameCodec有构造函数,netty推荐使用Http2FrameCodecBuilder来构造:Http2FrameCodecBuilder.forServer().build();你可以看到Http2FrameCodecBuilder有一个forServer和一个forClient方法。其中一个用于服务器端,另一个用于客户端。主要通过里面的server属性来区分。流生命周期帧编解码器将向有效流发送和写入帧。如前所述,Http2StreamFrame与Http2FrameStream对象相关联。对于有效的流,如果任何一方发送RST_STREAM帧,流将被关闭。或者如果发送方或接收方发送的帧中有END_STREAM标记,流也将被关闭。流量控制Http2FrameCodec提供了流量的自动控制,但是我们仍然需要做一些操作来更新窗口。具体来说,当我们收到Http2DataFrame消息时,我们需要在处理消息后增加窗口的大小,表示数据已经处理完毕,有更多的空间容纳新的数据。也就是说需要写一个Http2WindowUpdateFrame给ctx。在这个Http2WindowUpdateFrame中,需要传入需要处理的数据大小和对应流的id,下面是处理一个数据帧的例子:/***处理数据帧消息*/privatestaticvoidonDataRead(ChannelHandlerContextctx,Http2DataFrame数据){Http2FrameStreamstream=data.stream();如果(data.isEndStream()){sendResponse(ctx,stream,data.content());}else{//notendstream不发送,但需要释放引用data.release();}//处理完数据后,需要更新窗框,增加处理后Data的大小ctx.write(newDefaultHttp2WindowUpdateFrame(data.initialFlowControlledBytes()).stream(stream));在上面的示例中,我们将相应的流id传递给了DefaultHttp2WindowUpdateFrame。如果流id为0,则表示正在处理整个连接,而不是单个流。除了窗口更新帧之外,还可以为特定流的初始窗口发送一个Http2SettingsFrame,通过设置Http2Settings.initialWindowSize()可以达到初始化的目的。接收消息对于每一个HTTP/2流,其中包含的帧可以分为Http2HeadersFrame和Http2DataFrame,而Http2HeadersFrame一定是第一个接收到的帧,而这个headerFrame也关联着对应的流对象:Http2FrameStream。所以我们在处理的时候可以把这两个不同的帧分开处理:}elseif(msginstanceofHttp2DataFrame){onDataRead(ctx,(Http2DataFrame)msg??);}else{super.channelRead(ctx,msg);}}Customhandler如果使用Http2FrameCodec,我们只需要在pipline中添加Http2FrameCodec,然后添加一个customhandler就可以了:ctx.pipeline().addLast(Http2FrameCodecBuilder.forServer().build(),newCustHttp2Handler());因为Http2FrameCodec在http2中已经对frame进行了转换,所以我们只需要在CustHttp2Handler中处理自定义逻辑即可。Netty推荐自定义handler继承自Http2ChannelDuplexHandler,因为它比普通的ChannelDuplexHandler多了一个forEachActiveStream(Http2FrameStreamVisitor)方法来创建newStream()并遍历所有有效流。小结本文讲解了Http2FrameCodec的原理以及与其匹配的handler实现中的注意事项。本文示例可参考:learn-netty4本文已收录于http://www.flydean.com/31-netty-framecodec-http2/最流行的解读,最深刻的干货,最简洁的教程,很多你不知道的小技巧等你来发现!欢迎关注我的公众号:《程序那些事儿》,懂技术,更懂你!