如何使用Netty实现Http服务器
作者:鱼仔
博客首页: codeease.top (opens new window)
公众号:Java鱼仔
# 引言
之前在看XxlJob源码的时候,发现他用Netty实现了一个Http服务器,用来做调度中心和执行器之间的通信。这篇文章我们就用Netty去实现一个Http服务器。同时加深对Netty的理解。
netty版本选择4.1.90.Final
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
<version>4.1.90.Final</version>
</dependency>
1
2
3
4
5
2
3
4
5
# 服务端搭建
整体的搭建流程和之前写TCP的例子是一样的,定义bossGroup和workerGroup,再通过ServerBootstrap组装group,channel和handler。在ChannelPipeline中,先添加了一个netty提供的处理HTTP的编码器HttpServerCodec,然后再添加一个自定义的编码处理器,当接收到请求的时候,就在这个自定义的编码处理器中进行逻辑处理。
package com.spring.ease.example.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
/**
* @author by: 鱼仔
* @ClassName: FirstHttpServer
* @Description:
* @Date: 2024/11/8 15:32
*/
public class FirstHttpServer {
public static void main(String[] args) {
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
// netty提供的处理HTTP的编码器
pipeline.addLast("httpServerCodec", new HttpServerCodec());
// 增加一个自定义的编码处理器
pipeline.addLast("httpServerHandler",new MyHttpServerHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();
System.out.println("初始化完成,运行端口为:8080");
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
private static class MyHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
// 如果传输的是Http请求,才进行处理
if (httpObject instanceof HttpRequest) {
HttpRequest request = (HttpRequest) httpObject;
String uri = request.uri();
System.out.println("uri = " + uri);
// 跳过favicon.ico
String faviconUrl = "/favicon.ico";
if (faviconUrl.equals(uri)){
return;
}
//回复信息给浏览器 [http协议]
ByteBuf content = Unpooled.copiedBuffer("hello, 我是服务器", CharsetUtil.UTF_8);
//构造一个http的相应,即 httpresponse
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
//将构建好 response返回
channelHandlerContext.writeAndFlush(response);
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# 效果演示
运行项目之后,在控制台会输出一条消息:初始化完成,运行端口为:8080
接着在浏览器上访问:http://localhost:8080/test,收到代码中我们想让他输出的内容。
在控制台中,我们可以看到一共收到了两次请求,一次是我们正常的/test路径,另一次是/favicon.ico,后面的这一次请求是浏览器默认发起的行为,因此我在代码中跳过了它。
# 源码中的实践
xxl-job项目中,调度中心和任务执行器之间的交互,就是通过netty实现的http服务器,核心类是 EmbedServer
我现在贴出这个类中核心的代码:
具体的代码逻辑和我们上面自己写的是一样的,处理请求的逻辑在EmbedHttpServerHandler中
通过和我们类似的代码拿到uri之后,通过不同的 uri 后缀,触发执行器中对应的代码逻辑,从而实现了调度器能调度我们应用中的执行器的功能。
上次更新: 2025/02/18, 11:30:08