netty http server 实例
所属分类 netty
浏览量 68
netty 4.1.42.Final
server.HttpServer
server.HttpServerHandler
public interface RequestHandler {
Object handle(FullHttpRequest fullHttpRequest);
}
handler.GetRequestHandler
handler.PostRequestHandler
private static final int DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
@Slf4j
public class HttpServer {
private static final int PORT = 8080;
public void start() {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
// TCP默认开启 Nagle 算法,尽可能的发送大数据快,减少网络传输
// TCP_NODELAY 参数的作用就是控制是否启用 Nagle 算法。
.childOption(ChannelOption.TCP_NODELAY, true)
// 是否开启 TCP 底层心跳机制
.childOption(ChannelOption.SO_KEEPALIVE, true)
// 用于临时存放已完成三次握手的请求的队列的最大长度,如果连接建立频繁,服务器处理创建新连接较慢,可以适当调大该参数
.option(ChannelOption.SO_BACKLOG, 128)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline().addLast("decoder", new HttpRequestDecoder())
.addLast("encoder", new HttpResponseEncoder())
.addLast("aggregator", new HttpObjectAggregator(512 * 1024))
.addLast("handler", new HttpServerHandler());
}
});
Channel ch = b.bind(PORT).sync().channel();
log.info("Netty Http Server started on port {}.", PORT);
ch.closeFuture().sync();
} catch (InterruptedException e) {
log.error("occur exception when start server:", e);
} finally {
log.error("shutdown bossGroup and workerGroup");
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
@Slf4j
public class HttpServerHandler extends SimpleChannelInboundHandler< FullHttpRequest> {
private static final String FAVICON_ICO = "/favicon.ico";
private static final AsciiString CONNECTION = AsciiString.cached("Connection");
private static final AsciiString KEEP_ALIVE = AsciiString.cached("keep-alive");
private static final AsciiString CONTENT_TYPE = AsciiString.cached("Content-Type");
private static final AsciiString CONTENT_LENGTH = AsciiString.cached("Content-Length");
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) {
log.info("Handle http request:{}", fullHttpRequest);
String uri = fullHttpRequest.uri();
if (uri.equals(FAVICON_ICO)) {
return;
}
RequestHandler requestHandler = RequestHandlerFactory.create(fullHttpRequest.method());
Object result;
FullHttpResponse response;
try {
result = requestHandler.handle(fullHttpRequest);
String responseHtml = "" + result + "";
byte[] responseBytes = responseHtml.getBytes(StandardCharsets.UTF_8);
response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(responseBytes));
response.headers().set(CONTENT_TYPE, "text/html; charset=utf-8");
response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());
} catch (IllegalArgumentException e) {
e.printStackTrace();
String responseHtml = "" + e+"" + "";
byte[] responseBytes = responseHtml.getBytes(StandardCharsets.UTF_8);
response = new DefaultFullHttpResponse(HTTP_1_1, INTERNAL_SERVER_ERROR, Unpooled.wrappedBuffer(responseBytes));
response.headers().set(CONTENT_TYPE, "text/html; charset=utf-8");
}
boolean keepAlive = HttpUtil.isKeepAlive(fullHttpRequest);
if (!keepAlive) {
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
} else {
response.headers().set(CONNECTION, KEEP_ALIVE);
ctx.write(response);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
}
@Slf4j
public class GetRequestHandler implements RequestHandler {
@Override
public Object handle(FullHttpRequest fullHttpRequest) {
String requestUri = fullHttpRequest.uri();
Map queryParameterMappings = this.getQueryParams(requestUri);
return queryParameterMappings.toString();
}
private Map getQueryParams(String uri) {
QueryStringDecoder queryDecoder = new QueryStringDecoder(uri, Charsets.toCharset(CharEncoding.UTF_8));
Map> parameters = queryDecoder.parameters();
Map queryParams = new HashMap<>();
for (Map.Entry> attr : parameters.entrySet()) {
for (String attrVal : attr.getValue()) {
queryParams.put(attr.getKey(), attrVal);
}
}
return queryParams;
}
}
@Slf4j
public class PostRequestHandler implements RequestHandler {
@Override
public Object handle(FullHttpRequest fullHttpRequest) {
String requestUri = fullHttpRequest.uri();
log.info("request uri :[{}]", requestUri);
String contentType = this.getContentType(fullHttpRequest.headers());
if (contentType.equals("application/json")) {
return fullHttpRequest.content().toString(Charsets.toCharset(CharEncoding.UTF_8));
} else {
throw new IllegalArgumentException("only receive application/json type data");
}
}
private String getContentType(HttpHeaders headers) {
String typeStr = headers.get("Content-Type");
String[] list = typeStr.split(";");
return list[0];
}
}
get
http://127.0.0.1:8080/hello?id=1&name=tiger
{name=tiger, id=1}
post
http://127.0.0.1:8080/hello
hello
{"id":1,"name":"tiger"}
https://gitee.com/dyyx/work2024/tree/master/demo/nettydemo/http-server
基于netty的RESTFUL框架
基于netty的 简单 rpc 框架
ChannelPipeline和ChannelInitializer
上一篇
下一篇
MQTT与WebSocket
WebSocket通信过程及原理
websocket 聊天室简单例子
netty 趣事
Netty ChannelPipeline Inbound Outbound
netty 架构原理简介