一,需求
文件服务器使用HTTP协议对外提供服务。用户通过浏览器访问文件服务器,首先对URL进行检查,若失败返回403错误;若通过校验,以链接的方式打开当前目录,每个目录或文件都以超链接的形式展现,可递归访问,并下载文件。
二,关键实现代码
①文件服务器启动类
需要添加的通道处理器如下:
@Overrideprotected void initChannel(SocketChannel ch) throwsException {
ch.pipeline().addLast("http-decoder", newHttpRequestDecoder());
ch.pipeline().addLast("http-aggregator", new HttpObjectAggregator(65536));
ch.pipeline().addLast("http-encoder", newHttpResponseEncoder());
ch.pipeline().addLast("http-chunked", newChunkedWriteHandler());
ch.pipeline().addLast("fileServerHandler", newHttpFileServerHandler(url));
}
1) HttpRequestDecoder
Decodes {@link ByteBuf}s into {@link HttpRequest}s and {@link HttpContent}s.
它负责把字节解码成Http请求。
2) HttpObjectAggregator
A {@link ChannelHandler} that aggregates an {@link HttpMessage} and its following {@link HttpContent}s into a single {@link FullHttpRequest} or {@link FullHttpResponse} (depending on if it used to handle requests or responses)
它负责把多个HttpMessage组装成一个完整的Http请求或者响应。到底是组装成请求还是响应,则取决于它所处理的内容是请求的内容,还是响应的内容。这其实可以通过Inbound和Outbound来判断,对于Server端而言,在Inbound 端接收请求,在Outbound端返回响应。
It is useful when you don't want to take care of HTTP messages whose transfer encoding is 'chunked'.
如果Server向Client返回的数据指定的传输编码是 chunked。则,Server不需要知道发送给Client的数据总长度是多少,它是通过分块发送的,参考分块传输编码
Be aware that you need to have the {@link HttpResponseEncoder} or {@link HttpRequestEncoder} before the {@link HttpObjectAggregator} in the {@link ChannelPipeline}.
注意,HttpObjectAggregator通道处理器必须放到HttpRequestDecoder或者HttpRequestEncoder后面。
3) HttpResponseEncoder
当Server处理完消息后,需要向Client发送响应。那么需要把响应编码成字节,再发送出去。故添加HttpResponseEncoder处理器。
4)ChunkedWriteHandler
A {@link ChannelHandler} that adds support for writing a large data stream asynchronously neither spending a lot of memory nor getting {@link OutOfMemoryError}.
该通道处理器主要是为了处理大文件传输的情形。大文件传输时,需要复杂的状态管理,而ChunkedWriteHandler实现这个功能。
5) HttpFileServerHandler
自定义的通道处理器,其目的是实现文件服务器的业务逻辑。
通道处理器添加完毕之后,需要启动服务器。代码如下:
ChannelFuture f = b.bind("localhost", port).sync();
f.channel().closeFuture().sync();
因为在Netty中所有的事件都是异步的,因此bind操作是一个异步操作,通道的关闭也是一个异步操作。因此使用ChannelFuture来作为一个 palceholder,代表操作执行之后的结果。
最后关闭事件线程,代码如下:
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
②文件处理器类
HttpFileServerHandler.java是自定义的通道处理器,用来实现HTTP文件服务器的业务逻辑。从上面添加的Handler可以看出,在HTTP文件服务器的实现过程中,Netty已经为我们解决了很多工作,如:HttpRequestDecoder自动帮我们解析HTTP请求(解析byte);再比如:HttpObjectAggregator把多个HTTP请求中的数据组装成一个,当服务器发送的response事先不知道响应的长度时就很有用。
文件处理器通过继承SimpleChannelInboundHandler来实现,代码如下:
public class HttpFileServerHandler extends SimpleChannelInboundHandler{private finalString url;publicHttpFileServerHandler(String url) {this.url =url;
}
@Overrideprotected voidmessageReceived(ChannelHandlerContext ctx,
FullHttpRequest request)throwsException {if(!request.d