zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    Palindrome Partitioning
    triangle
    Populating Next Right Pointers in Each Node(I and II)
    分苹果(网易)
    Flatten Binary Tree to Linked List
    Construct Binary Tree from Inorder and Postorder Traversal(根据中序遍历和后序遍历构建二叉树)
    iOS系统navigationBar背景色,文字颜色处理
    登录,注销
    ios 文字上下滚动效果Demo
    经常崩溃就是数组字典引起的
  • 原文地址:https://www.cnblogs.com/coderJiebao/p/Netty08.html
Copyright © 2011-2022 走看看