简单案例
先照常写一个Handler,注意收到的是HttpObject(实际上是一个DefaultHttpRequest)类型。它附带了客户端的请求信息(uri、请求method、请求头)
public class TestHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
//读取事件
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
if(msg instanceof HttpRequest){
System.out.println("msg 类型="+msg.getClass());
System.out.println("客户端地址" + ctx.channel().remoteAddress());
//构建HttpResponse
ByteBuf content = Unpooled.copiedBuffer("hello,我是服务器", CharsetUtil.UTF_8);
DefaultFullHttpResponse 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
ctx.writeAndFlush(response);
}
}
}
在ChannelInitializer这里,为channel的pipeline添加上面写的handler。注意在前面添加一个HttpServerCodec,是Netty提供的基于HTTP的编解码器。
public class TestServerInitializer extends ChannelInitializer<SocketChannel> {
protected void initChannel(SocketChannel ch) throws Exception {
//向管道加入处理器
//得到管道
ChannelPipeline pipeline = ch.pipeline();
//加入netty提供的httpServerCodec (coder+decoder)
//基于HTTP的编解码器
pipeline.addLast("MyHttpServerCodec",new HttpServerCodec());
pipeline.addLast("MyTestHttpServerHandler",new TestHttpServerHandler());
}
}
启动服务端的代码:
public class TestHttpServer {
public void bind(int port) throws Exception{
//配置服务器的NIO线程组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try{
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new TestServerInitializer());
System.out.println("---------服务器正在启动---------");
ChannelFuture future = serverBootstrap.bind(port).sync();
//等待服务端监听端口关闭
future.channel().closeFuture().sync();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 8080;
new TestHttpServer().bind(8080);
}
}
这样一个简单案例就实现了,只要客户端向该服务端的主机、端口发起HTTP请求,就会收到对应的响应,而由于没有判断请求方法、uri,无论什么请求都会收到一样的响应。
对请求资源(uri)进行过滤
浏览器在对某网站发起get请求的时候,通常还会发起对该网站/favicon.ico
的请求,如果我们不想对这个请求做出404回应,可以这样写:
public class TestHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
//读取事件
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
if(msg instanceof HttpRequest){
System.out.println("msg 类型="+msg.getClass());
System.out.println("客户端地址" + ctx.channel().remoteAddress());
//获取到请求URI
HttpRequest httpRequest = (HttpRequest) msg;
URI uri = new URI(httpRequest.uri());
if("/favicon.ico".equals(uri.getPath())){
System.out.println("请求了图标,返回404");
ByteBuf error = Unpooled.copiedBuffer("该资源不存在", CharsetUtil.UTF_8);
DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND, error);
response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain; charset=utf-8");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH,error.readableBytes());
ctx.writeAndFlush(response);
return;
}
//构建HttpResponse
ByteBuf content = Unpooled.copiedBuffer("hello,我是服务器", CharsetUtil.UTF_8);
DefaultFullHttpResponse 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
ctx.writeAndFlush(response);
}
}
}
这里通过HttpRequest来获取了客户端请求的uri,除了uri外,通过HttpRequest还可以获取:
httpRequest.method()
:获取请求方法,这些方法在HttpMethod中被枚举httpRequest.protocolVersion()
:获取协议版本,是HttpVersion.HTTP_1_0
或HttpVersion.HTTP_1_1
httpRequest.headers()
:请求头,可读可写,使用get/set方法
其他handler
在简单案例中只用了一个HttpServerCodec作为http编解码器,还有一些自带的handler可以使用:
HttpObjectAggregator
,对于POST请求存在请求体,HTTP数据在传输过程中是分段传输的,HttpObjectAggregator可以将多个段聚合。ChunkedWriteHandler
,在简单案例中,我们用了响应头的CONTENT_LENGTH
来指定响应体的长度,而有的时候无法确定信息大小,就可以使用Chunked编码传输(分块)。
原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/netty%e5%9f%ba%e4%ba%8ehttp%e5%8d%8f%e8%ae%ae%e7%9a%84%e6%9c%8d%e5%8a%a1%e7%ab%af%e5%bc%80%e5%8f%91/