12-Netty 高性能架构设计-基于Netty开发HTTP服务
快速入门实例-HTTP 服务
- D实例要求:使用IDEA创建Netty项目
- Netty服务器在6668端口监听,浏览器发出请求“http://localhost:6668/
- 服务器可以回复消息给客户端“Hello!我是服务器5”,并对特定请求资源进行过滤
- 目的:Netty可以做Http服务开发,并且理解Handler实例和客户端及其请求的关系
- 看老师代码演示
新建HttpServer
package com.dance.netty.netty.http; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelOption; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; /** * HTTP 服务器 */ public class HttpServer { public static void main(String[] args) { NioEventLoopGroup boosGroup = new NioEventLoopGroup(); NioEventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(boosGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new HttpServerInitializer()); ChannelFuture sync = serverBootstrap.bind("127.0.0.1",80).sync(); sync.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); } finally { boosGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }
新建HttpServerInitializer
package com.dance.netty.netty.http; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.ServerSocketChannel; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.http.HttpServerCodec; /** * 通道初始化 */ public class HttpServerInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { // 向管道加入处理器 ChannelPipeline pipeline = socketChannel.pipeline(); // 加入一个Netty提供的 HttpServerCodec codec => [coder - decoder] /* HttpServerCodec 是Netty提供的处理HTTP的 */ pipeline.addLast("MyHttpServer", new HttpServerCodec()); // 添加自己的处理器 pipeline.addLast("MyHandler", new HttpServerHandler()); } }
新建HttpServerHandler
package com.dance.netty.netty.http; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.*; import java.nio.charset.StandardCharsets; /** * 管道处理器 * SimpleChannelInboundHandler 继承了 ChannelInboundHandlerAdapter * HttpObject 客户端和服务器相互通讯的数据定义 */ public class HttpServerHandler extends SimpleChannelInboundHandler<HttpObject> { /** * 读取客户端数据 * @param channelHandlerContext 上下文对象 * @param msg httpObject对象 * @throws Exception 异常 */ @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject msg) throws Exception { // 判断是不是HttpRequest if(msg instanceof HttpRequest){ System.out.println("msg type is " + msg.getClass()); System.out.println("client address is " + channelHandlerContext.channel().remoteAddress()); // 回复信息给浏览器 [HTTP协议] ByteBuf byteBuf = Unpooled.copiedBuffer("Hello 我是服务器~", StandardCharsets.UTF_8); // 构造一个HTTP的响应, 即 HttpResponse DefaultFullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf); // 设置响应信息 httpResponse.headers() .set(HttpHeaderNames.CONTENT_TYPE, "text/plain;Charset=UTF-8") .set(HttpHeaderNames.CONTENT_LENGTH, byteBuf.readableBytes()); channelHandlerContext.writeAndFlush(httpResponse); } } }
测试
这里存在一个问题,那就是端口问题,之前是6668 chrome 访问直接被阻止
还有就是,在返回的类型中需要设置字符编码.不然会乱码
// 设置响应信息 httpResponse.headers() .set(HttpHeaderNames.CONTENT_TYPE, "text/plain;Charset=UTF-8") .set(HttpHeaderNames.CONTENT_LENGTH, byteBuf.readableBytes());
但是还是有一个问题的, 我访问了一次,但是控制台却显示的是两次
原因是应为在浏览器加载资源 的时候,同时请求了页面浏览器角标
就是这个东西
修改HttpServerHandler
package com.dance.netty.netty.http; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.*; import java.nio.charset.StandardCharsets; /** * 管道处理器 * SimpleChannelInboundHandler 继承了 ChannelInboundHandlerAdapter * HttpObject 客户端和服务器相互通讯的数据定义 */ public class HttpServerHandler extends SimpleChannelInboundHandler<HttpObject> { /** * 读取客户端数据 * @param channelHandlerContext 上下文对象 * @param msg httpObject对象 * @throws Exception 异常 */ @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject msg) throws Exception { // 判断是不是HttpRequest if(msg instanceof HttpRequest){ // 进行资源过滤 String uri = ((HttpRequest) msg).uri(); // 如果是图标直接结束 if(uri.endsWith("favicon.ico")){ System.out.println("request is favicon.ico, no result"); return; } ............. } } }
重启后测试
可以看到角标被过滤了