Netty实现HTTP服务器

本文介绍如何使用Netty快速搭建一个简单的HTTP服务器,并通过实例演示了文件服务的实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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目录下,就可以被访问到了。
image.png
访问:http://127.0.0.1:9999/static/index.html即可看到效果了。
image.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小潘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值