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

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

目录



简介


上一篇文章中,我们提到了如何在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服务器。

相关文章
|
17天前
使用Netty实现文件传输的HTTP服务器和客户端
本文通过详细的代码示例,展示了如何使用Netty框架实现一个文件传输的HTTP服务器和客户端,包括服务端的文件处理和客户端的文件请求与接收。
29 1
使用Netty实现文件传输的HTTP服务器和客户端
|
1月前
|
开发者
HTTP状态码是由网页服务器返回的三位数字响应代码,用于表示请求的处理结果和状态
HTTP状态码是由网页服务器返回的三位数字响应代码,用于表示请求的处理结果和状态
27 1
|
2月前
|
缓存 数据安全/隐私保护 UED
代理服务器在HTTP请求中的应用:Ruby实例
代理服务器在HTTP请求中的应用:Ruby实例
|
3月前
|
存储 运维 Java
函数计算产品使用问题之如何使用Python的requests库向HTTP服务器发送GET请求
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
102 8
|
2月前
|
移动开发 网络协议 编译器
实战案例3:C语言实现的HTTP服务器
实战案例3:C语言实现的HTTP服务器
92 0
|
3月前
|
缓存 程序员 开发者
HTTP状态码大全:如何读懂服务器的语言?
大家好,我是小米,今天我们来聊聊HTTP协议中的GET和POST请求。它们在数据传输方式、安全性和应用场景上有不同特点。本文将详细解析它们的区别和特点,帮助你更好地理解和运用这两种请求方式。让我们一起学习吧!
61 1
|
Java 安全 API
Netty:一个非阻塞的客户端/服务器框架
版权声明:本文为博主chszs的原创文章,未经博主允许不得转载。 https://blog.csdn.net/chszs/article/details/40151331 Netty:一个非阻塞的客户端/服务器框架 作者:chszs,转载需注明。
997 0
|
Java 安全 API
Netty:一个非阻塞的客户端/服务器框架
Netty:一个非阻塞的客户端/服务器框架 Netty是一个异步事件驱动的网络应用框架,为Java网络应用的开发带来了一些新活力。Netty由协议服务器和客户端所组成,可用于快速开发可维护的高性能软件。
1282 0
|
存储 缓存 NoSQL
跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)
本文将要分享的是如何从零实现一套基于Netty框架的分布式高可用IM系统,它将支持长连接网关管理、单聊、群聊、聊天记录查询、离线消息存储、消息推送、心跳、分布式唯一ID、红包、消息同步等功能,并且还支持集群部署。
13473 1
|
5月前
|
消息中间件 Oracle Dubbo
Netty 源码共读(一)如何阅读JDK下sun包的源码
Netty 源码共读(一)如何阅读JDK下sun包的源码
121 1

热门文章

最新文章