用Netty搭建一个简单的Http服务器,实现客户端发起http请求时,服务端作出响应返回一串数据。
准备工作
搭建maven项目,引入netty的依赖。我这里用的是4.0.20版本。
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.0.20.Final</version>
</dependency>
代码编写
1、启动服务端
public class HttpServer {
public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//设置启动参数
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
//自定义childHandler =》 HttpChannelInitializer
.childHandler(new HttpChannelInitializer());
//启动服务端
ChannelFuture channelFuture = serverBootstrap.bind("127.0.0.1",8989).sync();
channelFuture.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture channelFuture) throws Exception {
if (channelFuture.isSuccess()) {
System.out.println("服务器启动成功");
}else {
System.out.println("服务器启动失败");
}
}
});
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
2、自定义childHandler,继承ChannelInitializer类
public class HttpChannelInitializer extends ChannelInitializer<SocketChannel> {
protected void initChannel(SocketChannel socketChannel) throws Exception {
//获取pipeline
ChannelPipeline pipeline = socketChannel.pipeline();
//HttpServerCodec:encode & decode
pipeline.addLast(new HttpServerCodec());
//自定义handler
pipeline.addLast(new HttpChannelHandler());
}
}
3、自定义请求处理类,继承SimpleChannelInboundHandler类,HttpObject是一个接口,有包括request和response等子类。
这里有一个问题,每次浏览器请求会带上一个favicon.ico图标的请求,我们可以通过得到的路径进行过滤。
public class HttpChannelHandler extends SimpleChannelInboundHandler<HttpObject> {
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
//ctx里可以获取很多内容,比如客户端的ip
System.out.println(ctx.channel().remoteAddress());
if (msg instanceof HttpRequest) {
HttpRequest request = (HttpRequest) msg;
//过滤图标的请求
if ("/favicon.ico".equals(request.getUri())) {
System.out.println("不做处理");
return;
}
}
//给客户端回传数据
ByteBuf byteBuf = Unpooled.copiedBuffer("hello~我是服务器~", CharsetUtil.UTF_8);
//使用DefaultFullHttpResponse作为response
DefaultFullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);
//设置头信息,以及编码,防止乱码
response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain;charset=utf8");
response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, byteBuf.readableBytes());
//回写数据
ctx.writeAndFlush(response);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
ctx.close();
}
}
有几个问题需要注意一下。
1、不同的客户端进来,是同一个handler做处理吗?
2、每次刷新请求,还是之前的handler在做处理吗?
解答:
对handler的hashcode和Pipline的hashcode作出打印。
1、用两个浏览器请求同一个请求所得到的handler和Pipline的哈希是不同的。
2、浏览器一刷新,所得到的handler和Pipline的哈希也是不同的。
因为http请求每次一结束他就断掉了,重新访问就会产生一个新的做处理。