Netty入门(八)构建Netty HTTP/HTTPS应用

  HTTP/HTTPS 是最常见的一种协议,这节主要是看一下 Netty 提供的 ChannelHaandler。

一、HTTP Decoder,Encoder 和 Codec

  HTTP 是请求-响应模式,客户端发送一个 HTTP 请求,服务就响应此请求。

  HttpRequest 包格式如下:

  

  1.  包头
  2.  数据部分,后续可以有多个 HttpContent 部分
  3.  包尾,标记 request 包结束,同时可能包含头的尾部信息
  4.  完整的 HTTP request

  HttpResponce 包格式如下:

  

  1.  包头
  2.  数据部分,后续可以有多个 HttpContent 部分
  3.  包尾,标记 responce 包结束,同时可能包含头的尾部信息
  4.  完整的 HTTP responce

   下面是 Netty 提供的解码器和编码器用来处理上述的包信息:

  

  所以,如果我们想要在应用程序中支持 HTTP,只需要添加正确的 ChannelHandler 到 ChannelPipeline 中即可:

 1 public class HttpPipelineInitializer extends ChannelInitializer<Channel> {
 2     private final boolean client;
 3     
 4     public HttpPipelineInitializer(boolean client) {
 5         this.client = client;
 6     }
 7     
 8     @Override
 9     protected void initChannel(Channel ch) throws Exception {
10         ChannelPipeline pipeline = ch.pipeline();
11         if(client) {
12             // 客户端需要解码服务器响应,编码客户端请求
13             pipeline.addLast("decoder", new HttpResponseDecoder());
14             pipeline.addLast("encoder", new HttpRequestEncoder());
15         } else {
16             // 服务端需要解码客户端请求,编码服务端响应
17             pipeline.addLast("decoder", new HttpRequestDecoder());
18             pipeline.addLast("encoder", new HttpResponseEncoder());
19         }
20     }
21 
22 }

 二、HTTP 消息聚合

   由于 HTTP 请求和响应消息部分可以由许多块组成,我们需要聚合它们形成完整的消息。Netty 提供了一个聚合器。如下为简单实现:

 1 /**
 2  * HTTP 消息聚合
 3  * HttpObjectAggregator
 4  */
 5 public class HttpAggregatorInitializer extends ChannelInitializer<Channel> {
 6     private final boolean client;
 7     
 8     public HttpAggregatorInitializer(boolean client) {
 9         this.client = client;
10     }
11 
12     @Override
13     protected void initChannel(Channel ch) throws Exception {
14         ChannelPipeline pipeline = ch.pipeline();
15         if(client) {
16             // 客户端
17             pipeline.addLast("codec", new HttpClientCodec());
18         } else {
19             // 服务器
20             pipeline.addLast("codec", new HttpServerCodec());
21         }
22         // HTTP聚合,设置最大消息值为512KB
23         pipeline.addLast("aggegator", new HttpObjectAggregator(512 * 1024));
24     }
25 
26 }

 三、HTTP 压缩

   使用 HTTP 时建议压缩数据以减少传输流量,Netty 支持 “gzip”和“deflate”。简单实现如下:

 1 /**
 2  * HTTP 压缩
 3  * HttpContentDecompressor 用于客户端解压缩
 4  * HttpContentCompressor 用于服务器压缩
 5  */
 6 public class HttpCompressorInitializer extends ChannelInitializer<Channel> {
 7     private final boolean client;
 8     
 9     public HttpCompressorInitializer(boolean client) {
10         this.client = client;
11     }
12     
13     @Override
14     protected void initChannel(Channel ch) throws Exception {
15         ChannelPipeline pipeline = ch.pipeline();
16         if(client) {
17             // 客户端
18             pipeline.addLast("codec", new HttpClientCodec());
19             // 解压缩,用于处理来自服务器的压缩内容
20             pipeline.addLast("decompressor", new HttpContentDecompressor());
21         } else {
22             // 服务端
23             pipeline.addLast("codec", new HttpServerCodec());
24             // 压缩,将要发送的消息压缩后再发出
25             pipeline.addLast("compressor", new HttpContentCompressor());
26         }
27     }
28 
29 }

 四、使用 HTTPS

  启动 HTTPS(比 HTTP 安全),只需添加 SslHandler。简单实现如下:

 1 /**
 2  * HTTPS
 3  */
 4 public class HttpsCodecInitializer extends ChannelInitializer<Channel> {
 5     private final SslContext context;
 6     private final boolean client;
 7     
 8     public HttpsCodecInitializer(SslContext context, boolean client) {
 9         this.context = context;
10         this.client = client;    
11     }
12 
13     @Override
14     protected void initChannel(Channel ch) throws Exception {
15         ChannelPipeline pipeline  = ch.pipeline();
16         SSLEngine engine = context.newEngine(ch.alloc());
17         
18         // 添加SslHandler以启用HTTPS
19         pipeline.addFirst("ssl", new SslHandler(engine));
20         if(client) {
21             // 客户端
22             pipeline.addLast("codec", new HttpClientCodec());
23         } else {
24             // 服务端
25             pipeline.addLast("codec", new HttpServerCodec());
26         }
27     }
28     
29 }

 五、WebSocket

   WebSocket 允许数据双向传输,而不需要请求-响应模式。当我们需要服务器主动向客户端发送消息,比如实时系统,WebSocket 就是一个不错的选择。下面是一个通用的 WebSocket 协议:

  

  1.  Client(HTTP)与 Server 通讯
  2.  Server(HTTP)与 Client 通讯
  3.  Client 通过 HTTP(s) 来进行 WebSocket 握手,并等待确认
  4.  连接协议升级至 WebSocket

   应用程序支持 WebSocket 只需要添加适当的客户端或服务器端 WebSocket ChannelHandler 到管道。这个类将处理 WebSocket 定义的信息类型,称为“帧”。帧类型可分为数据帧和控制帧,如下:

  

  简单实现如下:

 1 /**
 2  * WebSocket
 3  * WebSocketServerProtocolHandler 处理其他类型帧
 4  * TextFrameHandler BinaryFrameHandler ContinuationFrameHandler
 5  */
 6 public class WebSocketServerInitializer extends ChannelInitializer<Channel> {
 7 
 8     @Override
 9     protected void initChannel(Channel ch) throws Exception {
10         ch.pipeline().addLast(
11                 new HttpServerCodec(),
12                 new HttpObjectAggregator(65536),        // HTTP 聚合
13                 // 处理除指定Frame之外的其他类型帧,比如Ping,Pong,Close等
14                 new WebSocketServerProtocolHandler("/websocket"),
15                 new TextFrameHandler(),
16                 new BinaryFrameHandler(),
17                 new ContinuationFrameHandler());
18     }
19 
20     // Text Frame
21     public static final class TextFrameHandler 
22         extends SimpleChannelInboundHandler<TextWebSocketFrame> {
23         @Override
24         protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
25             // TODO Handle Text Frame
26         }        
27     }
28     
29     // Binary Frame
30     public static final class BinaryFrameHandler 
31     extends SimpleChannelInboundHandler<BinaryWebSocketFrame> {
32         @Override
33         protected void channelRead0(ChannelHandlerContext ctx, BinaryWebSocketFrame msg) throws Exception {
34             // TODO Handle Text Frame
35         }
36     }
37     
38     // Continuation Frame
39     public static final class ContinuationFrameHandler 
40     extends SimpleChannelInboundHandler<ContinuationWebSocketFrame> {
41         @Override
42         protected void channelRead0(ChannelHandlerContext ctx, ContinuationWebSocketFrame msg) throws Exception {
43             // TODO Handle Text Frame
44         }
45     }
46 }

猜你喜欢

转载自www.cnblogs.com/coderJiebao/p/Netty08.html