@@ -35,8 +35,7 @@ Table 8.2 HTTP decoder and encoder
35
35
36
36
名称 | 描述
37
37
-----|----
38
- HttpRequestEncoder |Encodes HttpRequest , HttpContent and
39
- LastHttpContent messages to bytes.
38
+ HttpRequestEncoder |Encodes HttpRequest , HttpContent and LastHttpContent messages to bytes.
40
39
HttpResponseEncoder | Encodes HttpResponse, HttpContent and LastHttpContent messages to bytes.
41
40
HttpRequestDecoder | Decodes bytes into HttpRequest, HttpContent and LastHttpContent messages.
42
41
HttpResponseDecoder | Decodes bytes into HttpResponse, HttpContent and LastHttpContent messages.
@@ -71,3 +70,232 @@ Listing 8.2 Add support for HTTP
71
70
2 . client: 添加 HttpRequestEncoder 用于发送请求到 server
72
71
3 . server: 添加 HttpRequestDecoder 用于接收来自 client 的请求
73
72
4 . server: 添加 HttpResponseEncoder 用来发送响应给 client
73
+
74
+ ### HTTP消息聚合
75
+
76
+ 安装 ChannelPipeline 中的初始化之后,你能够对不同 HttpObject 消息进行操作。但由于 HTTP 请求和响应可以由许多部分组合而成,你需要聚合他们形成完整的消息。为了消除这种繁琐任务, Netty 提供了一个聚合器,合并消息部件到 FullHttpRequest 和 FullHttpResponse 消息。这样您总是能够看到完整的消息内容。
77
+
78
+ 这个操作有一个轻微的成本,消息段需要缓冲,直到完全可以将消息转发到下一个 ChannelInboundHandler 管道。但好处是,你不必担心消息碎片。
79
+
80
+ 实现自动聚合只需添加另一个 ChannelHandler 到 ChannelPipeline。清单8.3显示了这是如何实现的。
81
+
82
+ Listing 8.3 Automatically aggregate HTTP message fragments
83
+
84
+ public class HttpAggregatorInitializer extends ChannelInitializer<Channel> {
85
+
86
+ private final boolean client;
87
+
88
+ public HttpAggregatorInitializer(boolean client) {
89
+ this.client = client;
90
+ }
91
+
92
+ @Override
93
+ protected void initChannel(Channel ch) throws Exception {
94
+ ChannelPipeline pipeline = ch.pipeline();
95
+ if (client) {
96
+ pipeline.addLast("codec", new HttpClientCodec()); //1
97
+ } else {
98
+ pipeline.addLast("codec", new HttpServerCodec()); //2
99
+ }
100
+ pipeline.addLast("aggegator", new HttpObjectAggregator(512 * 1024)); //3
101
+ }
102
+ }
103
+
104
+ 1 . client: 添加 HttpClientCodec
105
+ 2 . server: 添加 HttpServerCodec 作为我们是 server 模式时
106
+ 3 . 添加 HttpObjectAggregator 到 ChannelPipeline, 使用最大消息值是 512kb
107
+
108
+
109
+ ### HTTP 压缩
110
+
111
+ 使用 HTTP 时建议压缩数据以减少传输流量,压缩数据会增加 CPU 负载,现在的硬件设施都很强大,大多数时候压缩数据时一个好主意。Netty 支持“gzip”和“deflate”,为此提供了两个 ChannelHandler 实现分别用于压缩和解压。看下面代码:
112
+
113
+ #### HTTP Request Header
114
+
115
+ 客户端可以通过提供下面的头显示支持加密模式。然而服务器不是,所以不得不压缩它发送的数据。
116
+
117
+ GET /encrypted-area HTTP/1.1
118
+ Host: www.example.com
119
+ Accept-Encoding: gzip, deflate
120
+
121
+ 下面是一个例子
122
+
123
+ Listing 8.4 Automatically compress HTTP messages
124
+
125
+ public class HttpAggregatorInitializer extends ChannelInitializer<Channel> {
126
+
127
+ private final boolean isClient;
128
+ public HttpAggregatorInitializer(boolean isClient) {
129
+ this.isClient = isClient;
130
+ }
131
+ @Override
132
+ protected void initChannel(Channel ch) throws Exception {
133
+ ChannelPipeline pipeline = ch.pipeline();
134
+ if (isClient) {
135
+ pipeline.addLast("codec", new HttpClientCodec()); //1
136
+ pipeline.addLast("decompressor",new HttpContentDecompressor()); //2
137
+ } else {
138
+ pipeline.addLast("codec", new HttpServerCodec()); //3
139
+ pipeline.addLast("compressor",new HttpContentCompressor()); //4
140
+ }
141
+ }
142
+ }
143
+
144
+ 1 . client: 添加 HttpClientCodec
145
+ 2 . client: 添加 HttpContentDecompressor 用于处理来自服务器的压缩的内容
146
+ 3 . server: HttpServerCodec
147
+ 4 . server: HttpContentCompressor 用于压缩来自 client 支持的 HttpContentCompressor
148
+
149
+ * 压缩与依赖*
150
+
151
+ * 注意,Java 6或者更早版本,如果要压缩数据,需要添加 [ jzlib] ( http://www.jcraft.com/jzlib/ ) 到 classpath*
152
+
153
+ <dependency>
154
+ <groupId>com.jcraft</groupId>
155
+ <artifactId>jzlib</artifactId>
156
+ <version>1.1.3</version>
157
+ </dependency>
158
+
159
+ ### 使用 HTTPS
160
+
161
+ 启用 HTTPS,只需添加 SslHandler
162
+
163
+ Listing 8.5 Using HTTPS
164
+
165
+ public class HttpsCodecInitializer extends ChannelInitializer<Channel> {
166
+
167
+ private final SslContext context;
168
+ private final boolean client;
169
+
170
+ public HttpsCodecInitializer(SslContext context, boolean client) {
171
+ this.context = context;
172
+ this.client = client;
173
+ }
174
+
175
+ @Override
176
+ protected void initChannel(Channel ch) throws Exception {
177
+ ChannelPipeline pipeline = ch.pipeline();
178
+ SSLEngine engine = context.newEngine(ch.alloc());
179
+ pipeline.addFirst("ssl", new SslHandler(engine)); //1
180
+
181
+ if (client) {
182
+ pipeline.addLast("codec", new HttpClientCodec()); //2
183
+ } else {
184
+ pipeline.addLast("codec", new HttpServerCodec()); //3
185
+ }
186
+ }
187
+ }
188
+
189
+ 1 . 添加 SslHandler 到 pipeline 来启用 HTTPS
190
+ 2 . client: 添加 HttpClientCodec
191
+ 3 . server: 添加 HttpServerCodec ,如果是 server 模式的话
192
+
193
+ 上面的代码就是一个很好的例子,解释了 Netty 的架构是如何让“重用”变成了“杠杆”。我们可以添加一个新的功能,甚至是一样重要的加密支持,几乎没有工作量,只需添加一个ChannelHandler 到 ChannelPipeline。
194
+
195
+ ### WebSocket
196
+
197
+ HTTP 是不错的协议,但是如果需要实时发布信息怎么做?有个做法就是客户端一直轮询请求服务器,这种方式虽然可以达到目的,但是其缺点很多,也不是优秀的解决方案,为了解决这个问题,便出现了 WebSocket。
198
+
199
+ WebSocket 允许数据双向传输,而不需要请求-响应模式。早期的WebSocket 只能发送文本数据,然后现在不仅可以发送文本数据,也可以发送二进制数据,这使得可以使用 WebSocket 构建你想要的程序。下图是WebSocket 的通信示例图:
200
+
201
+ WebSocket 规范及其实现是为了一个更有效的解决方案。简单的说,
202
+ 一个WebSocket 提供一个 TCP 连接两个方向的交通。结合 WebSocket API 它提供了一个替代 HTTP 轮询双向通信从页面到远程服务器。
203
+
204
+ 也就是说,WebSocket 提供真正的双向客户机和服务器之间的数据交换。
205
+ 我们不会对内部太多的细节,但我们应该提到,虽然最早实现仅限于文本数据,但现在不再是这样,WebSocket可以用于任意数据,就像一个正常的套接字。
206
+
207
+ 图8.4给出了一个通用的 WebSocket 协议。在这种情况下的通信开始于普通 HTTP ,并“升级”为双向 WebSocket。
208
+
209
+ ![ ] (../iamges/Figure 8.4 WebSocket protocol.jpg)
210
+
211
+
212
+ 1 . Client (HTTP) 与 Server 通讯
213
+ 2 . Server (HTTP) 与 Client 通讯
214
+ 3 . Client 通过 HTTP(s) 来进行 WebSocket 握手,并等待确认
215
+ 4 . 连接协议升级至 WebSocket
216
+
217
+ Figure 8.4 WebSocket protocol
218
+
219
+ 添加应用程序支持 WebSocket 只需要添加适当的客户端或服务器端WebSocket ChannelHandler 到管道。这个类将处理特殊 WebSocket 定义的消息类型,称为“帧。“如表8.3所示,这些可以归类为“数据”和“控制”帧。
220
+
221
+ Table 8.3 WebSocketFrame types
222
+
223
+ 名称 | 描述
224
+ -----|----
225
+ BinaryWebSocketFrame | Data frame: binary data
226
+ TextWebSocketFrame | Data frame: text data
227
+ ContinuationWebSocketFrame | Data frame: text or binary data that belongs to a previous BinaryWebSocketFrame or TextWebSocketFrame
228
+ CloseWebSocketFrame | Control frame: a CLOSE request, close status code and a phrase
229
+ PingWebSocketFrame | Control frame: requests the send of a PongWebSocketFrame
230
+ PongWebSocketFrame | Control frame: sent as response to a PingWebSocketFrame
231
+
232
+ 由于 Netty 的主要是一个服务器端技术重点在这里创建一个 WebSocket server 。清单8.6使用 WebSocketServerProtocolHandler 提出了一个简单的例子。该类处理协议升级握手以及三个“控制”帧 Close, Ping 和 Pong。Text 和 Binary 数据帧将被传递到下一个处理程序(由你实现)进行处理。
233
+
234
+ Listing 8.6 Support WebSocket on the server
235
+
236
+ public class WebSocketServerInitializer extends ChannelInitializer<Channel> {
237
+ @Override
238
+ protected void initChannel(Channel ch) throws Exception {
239
+ ch.pipeline().addLast(
240
+ new HttpServerCodec(),
241
+ new HttpObjectAggregator(65536), //1
242
+ new WebSocketServerProtocolHandler("/websocket"), //2
243
+ new TextFrameHandler(), //3
244
+ new BinaryFrameHandler(), //4
245
+ new ContinuationFrameHandler()); //5
246
+ }
247
+
248
+ public static final class TextFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
249
+ @Override
250
+ public void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
251
+ // Handle text frame
252
+ }
253
+ }
254
+
255
+ public static final class BinaryFrameHandler extends SimpleChannelInboundHandler<BinaryWebSocketFrame> {
256
+ @Override
257
+ public void channelRead0(ChannelHandlerContext ctx, BinaryWebSocketFrame msg) throws Exception {
258
+ // Handle binary frame
259
+ }
260
+ }
261
+
262
+ public static final class ContinuationFrameHandler extends SimpleChannelInboundHandler<ContinuationWebSocketFrame> {
263
+ @Override
264
+ public void channelRead0(ChannelHandlerContext ctx, ContinuationWebSocketFrame msg) throws Exception {
265
+ // Handle continuation frame
266
+ }
267
+ }
268
+ }
269
+
270
+
271
+ 1 . 添加 HttpObjectAggregator 用于提供在握手时聚合 HttpRequest
272
+ 2 . 添加 WebSocketServerProtocolHandler 用于处理色好给你寄握手如果请求是发送到"/websocket." 端点,当升级完成后,它将会处理Ping, Pong 和 Close 帧
273
+ 3 . TextFrameHandler 将会处理 TextWebSocketFrames
274
+ 4 . BinaryFrameHandler 将会处理 BinaryWebSocketFrames
275
+ 5 . ContinuationFrameHandler 将会处理ContinuationWebSocketFrames
276
+
277
+ * 加密 WebSocket*
278
+ * 只需插入 SslHandler 到作为 pipline 第一个 ChannelHandler*
279
+
280
+ 详见 [ Chapter 11 WebSocket] (../NETTY BY EXAMPLE/WebSockets.md)
281
+
282
+ ### SPDY
283
+
284
+ [ SPDY] ( http://www.chromium.org/spdy ) (读作“SPeeDY”)是Google 开发的基于 TCP 的应用层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验。SPDY 并不是一种用于替代 HTTP 的协议,而是对 HTTP 协议的增强。SPDY 实现技术:
285
+
286
+ * 压缩报头
287
+ * 加密所有
288
+ * 多路复用连接
289
+ * 提供支持不同的传输优先级
290
+
291
+ SPDY 主要有5个版本:
292
+
293
+ * 1 - 初始化版本,但没有使用
294
+ * 2 - 新特性,包含服务器推送
295
+ * 3 - 新特性包含流控制和更新压缩
296
+ * 3.1 - 会话层流程控制
297
+ * 4.0 - 流量控制,并与 HTTP 2.0 更加集成
298
+
299
+ SPDY 被很多浏览器支持,包括 Google Chrome, Firefox, 和 Opera
300
+
301
+ Netty 支持 版本 2 和 3 (包含3.1)的支持。这些版本被广泛应用,可以支持更多的用户。更多内容详见 [ Chapter 12] (../NETTY BY EXAMPLE/SPDY.md)
0 commit comments