Netty 本身就支持了 HTTP 协议,内置的 HttpServerCodec 可以针对 HTTP 协议进行编解码,开箱即用,非常方便。使用 Netty 来来实现一个简单的 HTTP 服务是非常简单的。
代码上传至 Gitee:https://gitee.com/panchanghe/netty-project
1. HttpServer
Http 服务的启动类,它主要是创建 ServerBootstrap 引导,让 Netty 服务可以跑起来。
public class HttpServer {
private final int port;
public HttpServer(int port) {
this.port = port;
}
public static void main(String[] args) {
new HttpServer(9999).start();
}
public void start() {
EventLoopGroup boss = new NioEventLoopGroup(1);
EventLoopGroup worker = new NioEventLoopGroup();
new ServerBootstrap()
.group(boss, worker)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.childHandler(new HttpChannelInitializer())
.localAddress(port)
.bind();
}
}
2. HttpChannelInitializer
ChannelHandler 的初始化类,当有新的客户端 Channel 接入时,它负责对 SocketChannel 的 Pipeline 进行初始化。
@ChannelHandler.Sharable
public class HttpChannelInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
// HTTP协议编解码器
sc.pipeline().addLast(new HttpServerCodec());
// HTTP聚合器,得到一个完整的HTTP请求和响应
sc.pipeline().addLast(new HttpObjectAggregator(1024 * 1024 * 10));
// 文件分块传输
sc.pipeline().addLast(new ChunkedWriteHandler());
// HTTP请求分发器
sc.pipeline().addLast(RequestDispatcher.INSTANCE);
}
}
3. RequestDispatcher
请求分发器,这里实现的比较简单,只针对文件做简单的响应,如果文件不存在,返回 404 页面。
@ChannelHandler.Sharable
public class RequestDispatcher extends SimpleChannelInboundHandler<FullHttpRequest> {
public static RequestDispatcher INSTANCE = new RequestDispatcher();
private static File BASE_FILE;
static {
BASE_FILE = new File(RequestDispatcher.class.getResource("/static").getFile());
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
String uri = request.uri();
if (uri.startsWith("/static")) {
// 文件传输
File diskFile = new File(BASE_FILE, uri.replace("/static/", ""));
if (diskFile.exists()) {
writeFile(diskFile, ctx, request);
}else {
// 404
write404(ctx, request);
}
}
}
// 404页
private static void write404(ChannelHandlerContext ctx, FullHttpRequest request) {
HttpResponse response = new DefaultHttpResponse(request.protocolVersion(), HttpResponseStatus.NOT_FOUND);
ByteBuf buf = ctx.alloc().directBuffer().writeBytes("<h1>404</h1>".getBytes());
response.headers().add(HttpHeaderNames.CONTENT_TYPE, "text/html");
response.headers().add(HttpHeaderNames.CONTENT_LENGTH, buf.readableBytes());
ctx.write(response);
ctx.write(buf);
ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
}
// 响应文件
private static void writeFile(File diskFile, ChannelHandlerContext ctx, FullHttpRequest request) {
try {
// 文件传输
HttpResponse response = new DefaultHttpResponse(request.protocolVersion(), HttpResponseStatus.OK);
RandomAccessFile file = new RandomAccessFile(diskFile, "r");
FileRegion fileRegion = new DefaultFileRegion(file.getChannel(), 0, file.length());
response.headers().add(HttpHeaderNames.CONTENT_LENGTH, file.length());
ctx.write(response);
ctx.write(fileRegion);
ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
}catch (Exception e){
e.printStackTrace();
}
}
}
4. 测试
我在网上找了一个网页模板,包含 Html、Css、Js,将它们放到项目的 static 目录下,就可以被访问到了。访问:http://127.0.0.1:9999/static/index.html即可看到效果了。
原文始发于微信公众号(程序员小潘):Netty实现HTTP服务器
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/29418.html