首页 > 其他分享 >netty系列之:使用netty实现支持http2的服务器

netty系列之:使用netty实现支持http2的服务器

时间:2022-08-15 15:34:39浏览次数:71  
标签:netty frame ctx HttpServerUpgradeHandler http2 Http2ConnectionHandler 服务器

目录

  • 简介
  • 基本流程
  • CleartextHttp2ServerUpgradeHandler
  • Http2ConnectionHandler
  • 总结

简介

上一篇文章中,我们提到了如何在netty中配置TLS,让他支持HTTP2。事实上TLS并不是https的一个必须要求,它只是建议的标准。那么除了TLS之外,还需要如何设置才能让netty支持http2呢?一起来看看吧。

基本流程

netty支持http2有两种情况,第一种情况是使用tls,在这种情况下需要添加一个ProtocolNegotiationHandler来对握手之后的协议进行协商,在协商之后,需要决定到底使用哪一种协议。

上一篇文章,我们已经介绍TLS支持http2的细节了,这里不再赘述,感兴趣的朋友可以查看我之前的文章。

如果不使用tls,那么有两种情况,一种是直接使用http1.1了,我们需要为http1.1添加一个ChannelInboundHandler即可。

另一种情况就是使用clear text从HTTP1.1升级到HTTP2。

HTTP/2 ClearText也叫做h2c,我们看一个简单的升级请求,首先是客户端请求:

GET /index HTTP/1.1
Host: server.flydean.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c 
HTTP2-Settings: (SETTINGS payload) 

然后是服务器端的响应,如果服务器端不支持升级,则返回:

HTTP/1.1 200 OK 
Content-length: 100
Content-type: text/html

(... HTTP/1.1 response ...)

如果服务器支持升级,则返回:

HTTP/1.1 101 Switching Protocols 
Connection: Upgrade
Upgrade: h2c

(... HTTP/2 response ...)

CleartextHttp2ServerUpgradeHandler

有了上面的基本流程,我们只需要在netty中提供对应的handler类就可以解决netty对http2的支持了。

不过上面的升级流程看起来比较复杂,所以netty为我们提供了一个封装好的类:CleartextHttp2ServerUpgradeHandler来实现h2c的功能。

这个类需要传入3个参数,分别是HttpServerCodec、HttpServerUpgradeHandler和ChannelHandler。

HttpServerCodec就是处理http server的编码类,一般我们使用HttpServerCodec。

HttpServerUpgradeHandler是从http1.1升级到http2的处理类。

netty也提供了一个现成的类:HttpServerUpgradeHandler,来处理升级的编码。

HttpServerUpgradeHandler需要两个参数,一个是sourceCodec,也就是http原始的编码类HttpServerCodec,一个是用来返回UpgradeCodec的工厂类,返回netty自带的Http2ServerUpgradeCodec。

    public HttpServerUpgradeHandler(SourceCodec sourceCodec, UpgradeCodecFactory upgradeCodecFactory) {
        this(sourceCodec, upgradeCodecFactory, 0);
    }

ChannelHandler是真正处理HTTP2的handler,我们可以根据需要对这个handler进行自定义。

有了UpgradeHandler,将其加入ChannelPipeline即可。

Http2ConnectionHandler

不管是HttpServerUpgradeHandler,还是CleartextHttp2ServerUpgradeHandler,都需要传入一个真正能够处理http2的handler。这个handler就是Http2ConnectionHandler。

Http2ConnectionHandler是一个实现类,它已经实现了处理各种inbound frame events的事件,然后将这些事件委托给 Http2FrameListener。

所以Http2ConnectionHandler需要跟Http2FrameListener配合使用。

这里要详细讲解一下Http2FrameListener,它主要处理HTTP2 frame的各种事件。

先来看下http2FrameListener中提供的event trigger方法:

从上图可以看到,主要是各种frame的事件触发方法,其中http2中有这样几种frame:

  • DATA frame
  • HEADERS frame
  • PRIORITY frame
  • RST_STREAM frame
  • SETTINGS acknowledgment frame
  • SETTINGS frame
  • PING frame
  • PING acknowledgment
  • PUSH_PROMISE frame
  • GO_AWAY frame
  • WINDOW_UPDATE frame
  • Unknown Frame

这几种frame基本上列举了http2 frame中所有的类型。

我们要做的就是自定义一个handler类,继承Http2ConnectionHandler,然后实现Http2FrameListener接口即可。

    public final class CustHttp2Handler extends Http2ConnectionHandler implements Http2FrameListener

在使用clear text从HTTP1.1升级到HTTP2的过程中,我们需要处理两个事情,第一个事情就是处理http1.1使用http头升级到http2,可以重写继承自Http2ConnectionHandler的userEventTriggered方法,通过判断event的类型是否是UpgradeEvent,来触发对应的Http2FrameListener接口中的方法,比如这里的onHeadersRead:

    /**
     * 处理HTTP upgrade事件
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof HttpServerUpgradeHandler.UpgradeEvent) {
            HttpServerUpgradeHandler.UpgradeEvent upgradeEvent =
                    (HttpServerUpgradeHandler.UpgradeEvent) evt;
            onHeadersRead(ctx, 1, upgradeToHttp2Headers(upgradeEvent.upgradeRequest()), 0 , true);
        }
        super.userEventTriggered(ctx, evt);
    }

upgradeToHttp2Headers方法将传入的FullHttpRequest,转换成为Http2Headers:

    private static Http2Headers upgradeToHttp2Headers(FullHttpRequest request) {
        CharSequence host = request.headers().get(HttpHeaderNames.HOST);
        Http2Headers http2Headers = new DefaultHttp2Headers()
                .method(HttpMethod.GET.asciiName())
                .path(request.uri())
                .scheme(HttpScheme.HTTP.name());
        if (host != null) {
            http2Headers.authority(host);
        }
        return http2Headers;
    }

还有一个要实现的方法,就是sendResponse方法,将数据写回给客户端,回写需要包含headers和data两部分,如下所示:

    /**
     * 发送响应数据到客户端
     */
    private void sendResponse(ChannelHandlerContext ctx, int streamId, ByteBuf payload) {
        Http2Headers headers = new DefaultHttp2Headers().status(OK.codeAsText());
        encoder().writeHeaders(ctx, streamId, headers, 0, false, ctx.newPromise());
        encoder().writeData(ctx, streamId, payload, 0, true, ctx.newPromise());
    }

总结

到此,一个处理clear text从HTTP1.1升级到HTTP2的handler就做好了。加上之前讲解的TLS扩展协议的支持,就构成了一个完整的支持http2的netty服务器。

标签:netty,frame,ctx,HttpServerUpgradeHandler,http2,Http2ConnectionHandler,服务器
From: https://www.cnblogs.com/shanheyongmu/p/16588471.html

相关文章

  • 服务器上的json类型的文件提示找不到
       搞layuimini时总提示菜单接口有误服务器上地图一直显示不出来,火狐打开F12,发现是找不到json的文件,本来还以为是IIS中"请求筛选"的问题,后来发现不是...解决办......
  • Springboot项目构建docker镜像发布到aliyun服务器
    一、1.先下载docker//1.先删除原本可能存在的dockeryumremove docker\         docker-client\         docker-client-late......
  • 最多可省19%!阿里云第七代云服务器ECS中国大陆地域调价通知
    一直以来,阿里云通过自研技术不断提高产品性能,降低产品使用门槛。为了激活企业创新发展,阿里云宣布让利用户,针对中国大陆地域的第六代和第七代云服务器ECS进行调价,用户最高......
  • 校正centos服务器时间
    1、安装NTPsudoyum-yinstallntp12、使用ntpdate测试NTPntpdatepool.ntp.org13、查看服务器时间date14、启动ntpddaemon,持续校准时间systemctlstartntpd15、......
  • Netty - ByteBuffer
     一、ByteBuffer使用    二、ByteBuffer结构      三、ByteBuffer常见API3.1分配空间allocateV.S.allocateDirect ......
  • 服务器无法登录之迷——login界面无限循环
         本周遇到了一个很奇葩的问题,客户的一台服务器无论如何都无法登录到机器系统里面去。可以肯定的是输入的登录密码是完全正确的,但是输入密码后,总在login登录界面无......
  • 保护SSH服务器连接的8种方法
    在Linux上保护SSH服务器连接的8种方法入门小站 入门小站 2022-07-1121:58 发表于湖北收录于合集#Linux478个#ssh6个SSH是一种广泛使用的协议,用于安全地访......
  • 服务器12种基本故障+排查方法
    服务器12种基本故障+排查方法入门小站 入门小站 2022-07-1022:12 发表于湖北收录于合集#Linux478个#windows14个#服务器5个加电类故障定义举例从上电(或......
  • Ubuntu17.10上安装FTP服务器 (vsftpd)
    我在Ubuntu17.10上安装FTP服务器(vsftpd)原创 入门小站 入门小站 2022-08-0622:43 发表于湖北收录于合集#Linux478个#ftp1个1.安装vsftpd更新可用软......
  • flask+uwsgi+nginx 搭建后端服务器
    1)构建flask服务安装创建虚拟环境安装flask##创建虚拟环境python3-mvenvvenv#安装flaskpipinstall--upgradepippipinstall-Usetuptoolspipinstal......