1. 程式人生 > >WebFlux+HTTP2連線測試

WebFlux+HTTP2連線測試

WebFlux+HTTP2連線測試

環境

JDK的最低版本是8
Ubuntu 18
Spring Boot 2.1.0.RELEASE
底層使用OpenSLL

在這裡插入圖片描述

程式碼

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</
artifactId
>
<version>2.1.0.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> <exclusions
>
<exclusion> <groupId>io.netty</groupId> <artifactId>netty-transport-native-epoll</artifactId> </exclusion> </exclusions> </dependency> <!-- https://mvnrepository.com/artifact/io.netty/netty-tcnative-boringssl-static -->
<dependency> <groupId>io.netty</groupId> <artifactId>netty-tcnative-boringssl-static</artifactId> <version>2.0.19.Final</version> </dependency> </dependencies>

Http2App.java

@SpringBootApplication
public class Http2App {
    public static void main(String[] args) throws Exception {
        new SpringApplicationBuilder(Http2App.class)
                .web(WebApplicationType.REACTIVE)
                .run(args);
    }

}

伺服器啟動

reactor.netty.tcp.TcpServerBind類的bind方法初始化SSL環境。
通過reactor.netty.channel.BootstrapHandlers類的finalizeHandler方法繫結初始handler。

最重要的handler是io.netty.handler.ssl.SslHandler。
它的主要功能是提供對SSL、TLS和StartTLS支援:

  • 開始握手
  • 握手,一旦開始以後就是自動的
  • 關閉SSL session(向對端傳送close_notify訊息),SSL session關閉以後就不可用了,你得增加新的
  • 重新開始一個SSL session,你要先在ChannelPipeline裡刪除已經關閉的SslHandler。然後再插入一個帶有SSLEngine的SslHandler,然後開始握手
  • 實現StartTLS。StartTLS一般分三步:
    • 客戶端傳送StartTLS請求
    • 伺服器傳送StartTLS響應
    • 客戶端開始SSL握手

伺服器啟動的時候,reactor.netty.http.server.HttpServerBind類apply方法,還完成了Http1OrH2Initializer的初始化工作。

				return BootstrapHandlers.updateConfiguration(b,
						NettyPipeline.HttpInitializer,
						new Http1OrH2Initializer(conf.decoder.maxInitialLineLength,
								conf.decoder.maxHeaderSize,
								conf.decoder.maxChunkSize,
								conf.decoder.validateHeaders,
								conf.decoder.initialBufferSize,
								conf.minCompressionSize,
								compressPredicate(conf.compressPredicate, conf.minCompressionSize),
								conf.forwarded,
								conf.cookieEncoder,
								conf.cookieDecoder));


註冊了reactor.netty.http.server.HttpServerBind$Http1OrH2Codec
Http1OrH2Codec最終註冊了流處理器Http2StreamBridgeHandler和Http2StreamFrameToHttpObjectCodec。

增加sslHandler

reactor.netty.tcp.SslProvider$SslSupportConsumer類的accept方法生成sslHandler

    sslHandler = sslProvider.getSslContext().newHandler(channel.alloc());

上面的方法,呼叫的是io.netty.handler.ssl.ReferenceCountedOpenSslContext類的下面的方法。其中,jdkCompatibilityMode是false

    @Override
    protected final SslHandler newHandler(ByteBufAllocator alloc, boolean startTls) {
        return new SslHandler(newEngine0(alloc, null, -1, false), startTls);
    }

握手過程

在這裡插入圖片描述

具體的通訊過程,由OpenSSL負責。netty-tcnative-boringssl-static主要通過io.netty.internal.tcnative.SSL類完成原生呼叫。

握手成功,由reactor.netty.tcp.SslProvider$SslReadHandler類處理SslHandshakeCompletionEvent事件。

				if (handshake.isSuccess()) {
					ctx.fireChannelActive();
				}
				else {
					ctx.fireExceptionCaught(handshake.cause());
				}

執行reactor.netty.http.server.HttpServerBind$Http1OrH2Codec類的configurePipeline方法。

p.addLast(NettyPipeline.HttpCodec, http2MultiplexCodecBuilder.build());

請求處理

reactor.netty.http.server.Http2StreamBridgeHandler類的channelRead方法處理Http2HeadersFrame訊息。

reactor.netty.http.server.HttpToH2Operations類的onInboundNext方法,處理Http2DataFrame和Http2HeadersFrame訊息。
reactor.netty.http.server.HttpServerOperations類的onInboundNext方法處理HttpRequest和HttpContent訊息。