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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM