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訊息。