• 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 }
  • 相关阅读:
    洛谷 P1363 幻想迷宫
    洛谷 P2872 [USACO07DEC]道路建设Building Roads
    字符编码
    python 基础数据类型
    python基础数据类型
    Python中的流程控制
    Python的入门基础
    计算机基础
    Java Random 随机数
    Java Array二维数组使用
  • 原文地址:https://www.cnblogs.com/coderJiebao/p/Netty08.html
Copyright © 2020-2023  润新知