本文目录导读:

我来为您展示一个完整的Netty实现HTTP服务器的案例,包含代码和详细说明。
Maven依赖配置
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.100.Final</version>
</dependency>
服务器主类
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class HttpServer {
private static final int PORT = 8080;
public static void main(String[] args) throws InterruptedException {
// 创建boss线程组:接收连接
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
// 创建worker线程组:处理I/O
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ServerInitializer());
// 绑定端口并启动服务
ChannelFuture channelFuture = bootstrap.bind(PORT).sync();
System.out.println("HTTP Server started on port " + PORT);
// 关闭服务器
channelFuture.channel().closeFuture().sync();
} finally {
// 优雅关闭
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
服务器初始化器
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.HttpServerExpectContinueHandler;
public class ServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// HTTP编解码器
pipeline.addLast("httpCodec", new HttpServerCodec());
// HTTP聚合器:将HTTP消息聚合成完整的请求
pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
// HTTP应答处理
pipeline.addLast("httpServerHandler", new HttpServerHandler());
// 添加压缩支持(可选)
// pipeline.addLast("compressor", new HttpContentCompressor());
}
}
HTTP请求处理器
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import java.util.HashMap;
import java.util.Map;
public class HttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
if (msg instanceof HttpRequest) {
HttpRequest request = (HttpRequest) msg;
// 处理HTTP请求
handleRequest(ctx, request);
} else if (msg instanceof HttpContent) {
// 处理请求内容(如POST body)
HttpContent content = (HttpContent) msg;
handleContent(ctx, content);
}
}
private void handleRequest(ChannelHandlerContext ctx, HttpRequest request) {
// 获取请求方法
HttpMethod method = request.method();
// 获取请求URI
String uri = request.uri();
System.out.println("Received " + method + " request for: " + uri);
// 获取请求头
HttpHeaders headers = request.headers();
// 处理不同路径的请求
String responseContent;
if ("/".equals(uri)) {
responseContent = generateHomePage();
} else if ("/api/user".equals(uri) && method == HttpMethod.GET) {
responseContent = handleUserApi();
} else if ("/api/test".equals(uri)) {
responseContent = handleTestApi(request);
} else {
responseContent = "404 - Not Found";
sendResponse(ctx, responseContent, HttpResponseStatus.NOT_FOUND);
return;
}
sendResponse(ctx, responseContent, HttpResponseStatus.OK);
}
private void handleContent(ChannelHandlerContext ctx, HttpContent content) {
// 读取POST请求的内容
ByteBuf buf = content.content();
if (buf.isReadable()) {
String requestBody = buf.toString(CharsetUtil.UTF_8);
System.out.println("Request body: " + requestBody);
// 在这里处理请求体
if (content instanceof LastHttpContent) {
System.out.println("Request content received completely");
}
}
}
private void sendResponse(ChannelHandlerContext ctx, String content, HttpResponseStatus status) {
// 创建响应内容
ByteBuf responseBuf = Unpooled.copiedBuffer(content, CharsetUtil.UTF_8);
// 创建FullHttpResponse
FullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
status,
responseBuf);
// 设置响应头
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, responseBuf.readableBytes());
// 添加CORS支持(可选)
response.headers().set(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
// 发送响应并关闭连接
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
private String generateHomePage() {
StringBuilder html = new StringBuilder();
html.append("<!DOCTYPE html>")
.append("<html>")
.append("<head>")
.append("<title>Netty HTTP Server</title>")
.append("<style>")
.append("body { font-family: Arial; text-align: center; padding-top: 50px; }")
.append("h1 { color: #333; }")
.append("</style>")
.append("</head>")
.append("<body>")
.append("<h1>Welcome to Netty HTTP Server</h1>")
.append("<p>This is a simple HTTP server implemented with Netty</p>")
.append("<p>Time: " + new java.util.Date() + "</p>")
.append("<p>Test APIs:</p>")
.append("<ul>")
.append("<li><a href='/api/user'>API Test</a></li>")
.append("<li><a href='/api/test?param=value'>Parameter Test</a></li>")
.append("</ul>")
.append("</body>")
.append("</html>");
return html.toString();
}
private String handleUserApi() {
Map<String, Object> user = new HashMap<>();
user.put("id", 1);
user.put("name", "张三");
user.put("age", 25);
user.put("email", "zhangsan@example.com");
return "JSON Response: " + user.toString();
}
private String handleTestApi(HttpRequest request) {
// 解析查询参数
QueryStringDecoder decoder = new QueryStringDecoder(request.uri());
Map<String, java.util.List<String>> params = decoder.parameters();
StringBuilder result = new StringBuilder();
result.append("Query Parameters:\n");
for (Map.Entry<String, java.util.List<String>> entry : params.entrySet()) {
result.append(entry.getKey()).append("=").append(entry.getValue()).append("\n");
}
return result.toString();
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.err.println("Error: " + cause.getMessage());
ctx.close();
}
}
完整示例:支持RESTful API的服务器
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
public class RestfulApiServer extends SimpleChannelInboundHandler<FullHttpRequest> {
private final Gson gson = new Gson();
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
String uri = request.uri();
HttpMethod method = request.method();
// 路由处理
if ("/api/hello".equals(uri) && method == HttpMethod.GET) {
handleHello(ctx);
} else if ("/api/posts".equals(uri) && method == HttpMethod.GET) {
handleGetPosts(ctx);
} else if ("/api/posts".equals(uri) && method == HttpMethod.POST) {
// 读取POST请求体的JSON数据
String content = request.content().toString(CharsetUtil.UTF_8);
handleCreatePost(ctx, content);
} else if (uri.startsWith("/api/posts/") && method == HttpMethod.GET) {
String id = uri.substring("/api/posts/".length());
handleGetPostById(ctx, id);
} else {
sendJsonResponse(ctx, "{\"error\":\"Not Found\"}", HttpResponseStatus.NOT_FOUND);
}
}
private void handleHello(ChannelHandlerContext ctx) {
JsonObject response = new JsonObject();
response.addProperty("message", "Hello from Netty REST API");
sendJsonResponse(ctx, response.toString(), HttpResponseStatus.OK);
}
private void handleGetPosts(ChannelHandlerContext ctx) {
// 模拟帖子数据
String mockData = "[{\"id\":1, \"title\":\"Post 1\"}, {\"id\":2, \"title\":\"Post 2\"}]";
sendJsonResponse(ctx, mockData, HttpResponseStatus.OK);
}
private void handleCreatePost(ChannelHandlerContext ctx, String content) {
// 解析JSON并创建帖子
JsonObject request = gson.fromJson(content, JsonObject.class);
String title = request.get("title").getAsString();
JsonObject response = new JsonObject();
response.addProperty("success", true);
response.addProperty("title", title);
response.addProperty("message", "Post created successfully");
sendJsonResponse(ctx, response.toString(), HttpResponseStatus.CREATED);
}
private void handleGetPostById(ChannelHandlerContext ctx, String id) {
JsonObject response = new JsonObject();
response.addProperty("id", id);
response.addProperty("title", "Post " + id);
sendJsonResponse(ctx, response.toString(), HttpResponseStatus.OK);
}
private void sendJsonResponse(ChannelHandlerContext ctx, String json, HttpResponseStatus status) {
ByteBuf content = Unpooled.copiedBuffer(json, CharsetUtil.UTF_8);
FullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
status,
content);
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
response.headers().set(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
测试方法
命令行测试
# GET请求
curl -X GET http://localhost:8080/
# 带参数的GET请求
curl -X GET "http://localhost:8080/api/test?param1=value1¶m2=value2"
# POST请求
curl -X POST http://localhost:8080/api/posts \
-H "Content-Type: application/json" \
-d '{"title":"My First Post"}'
浏览器访问
打开浏览器访问 http://localhost:8080/ 查看HTML页面
高级特性扩展
// 添加HTTPS支持
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.SelfSignedCertificate;
// 在ServerInitializer中添加SSL支持
public class SecureServerInitializer extends ChannelInitializer<SocketChannel> {
private final SslContext sslContext;
public SecureServerInitializer(SslContext sslContext) {
this.sslContext = sslContext;
}
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 添加SSL处理器
pipeline.addLast("ssl", sslContext.newHandler(ch.alloc()));
// 添加HTTP处理器
pipeline.addLast("httpCodec", new HttpServerCodec());
pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
pipeline.addLast("handler", new HttpServerHandler());
}
}
测试工具类
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class TestClient {
public static void main(String[] args) throws Exception {
// 测试GET请求
URL url = new URL("http://localhost:8080/api/user");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
int responseCode = conn.getResponseCode();
System.out.println("Response Code: " + responseCode);
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println("Response Body: " + response.toString());
}
}
-
核心组件:
HttpServerCodec:处理HTTP编解码HttpObjectAggregator:聚合HTTP消息SimpleChannelInboundHandler:处理具体请求
-
线程模型:
- Boss线程:接受连接
- Worker线程:处理I/O
-
异步处理:
- 使用
ChannelFuture进行异步操作 - 通过
addListener监听完成状态
- 使用
-
性能优化:
- 使用零拷贝特性
- 减少内存复制
- 支持长连接和连接池
这个案例提供了一个完整的Netty HTTP服务器实现,可以直接运行并测试,您可以根据自己的需求修改处理器逻辑来扩展功能。