前言:
当前兄弟们对“netty接收http请求”都比较讲究,各位老铁们都想要了解一些“netty接收http请求”的相关文章。那么小编也在网络上汇集了一些对于“netty接收http请求””的相关知识,希望我们能喜欢,朋友们一起来学习一下吧!1. 前言
我们通常使用 Netty 来开发 TCP 协议,一般的应用场景都是客户端和服务端长连接通讯的模式,其实,除了 TCP 协议之外 Netty 还支持其他常见的应用协议,比如:Http、WebSocket 等。我们所熟悉的 Tomcat 在 6.x 之后其实底层就是基于 Netty 去实现的。接下来我们主要讲解如何通过 Netty 开发支持 Http 协议服务端,客户端则是通过浏览器发起请求。
2. 学习目的
其实 Netty 开发 Http 协议在我们的开发当中其实并不常用,其主要的的应用场景是开发类型 Tomcat 这种类型的 Web 容器,有了成熟的 Tomcat、Jboss、WebLogic,不需要我们去重新造一遍轮子,但是为什么还需要去学习它呢?
学习本节主要有两个目的:
有助于以后学习 Tomcat 的原理,Tomcat 的通讯部分是基于 Netty 去实现的;有助于理解整个 Java 体系的通讯架构原理,很多我们平时使用最多、接触最多、熟练使用的技术,但是我们往往不懂得其底层原理是什么,Tomcat 和 Http 就是其中被广泛熟知,但是很少同学有兴趣去了解其原理的。3. 环境搭建
下面,我们将实现一个 Demo,具体需求如下:
使用 Netty 开发一个 Web 服务器,端口是 8080;客户端请求,则不再是使用 Netty 编写的客户端代码了,而是通过浏览器输入地址进行访问。服务端响应,我们的 Web 服务器往浏览器输出信息,并且能够在浏览器上打印相关信息。
环境搭建步骤:
创建一个 Maven 项目;导入 Netty 坐标。
实例:
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.6.Final</version></dependency>代码块123454. 代码实现
Netty 核心原理是对客户端发送过来的数据进行解码,以及给客户端发送数据时需要进行数据的编码。同样的原理,Netty 对于 Http 协议的开发,其实也是针对 Http 格式是数据进行编码和解码而已,并没有很多神奇的地方。当然我们对 Http 格式非常的熟悉,可以自己手工去实现这个复杂的过程,Netty 也考虑到了简化开发的复杂度,因此给我们提供了相应的编解码类。接下来,我们一起感受一下。
4.1. Netty 主启动类
public class TestServer { public static void main(String[] args) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap .group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<NioSocketChannel>() { protected void initChannel(NioSocketChannel ch) { ChannelPipeline pipeline = ch.pipeline(); //1.Netty提供的针对Http的编解码 pipeline.addLast(new HttpServerCodec()); //2.自定义处理Http的业务Handler pipeline.addLast(new TestHttpServerHandler()); } }); ChannelFuture channelFuture = serverBootstrap.bind(8080).sync(); channelFuture.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } }}
代码说明:
这个是 Netty 的基本模板类,跟我们之前写的并没有什么不同,只是它给我们提了一个特殊的类 HttpServerCodec,从字面上都能猜到它就是针对 Http 服务的编解码器。
4.2. Netty 业务 Handler 类
public class TestHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> { @Override protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { if(msg instanceof HttpRequest) { //1.打印浏览器的请求地址 System.out.println("客户端地址:" + ctx.channel().remoteAddress()); //2.给浏览器发送的信息,封装成ByteBuf ByteBuf content = Unpooled.copiedBuffer("hello world", CharsetUtil.UTF_8); //3.构造一个http的相应,即 httpresponse FullHttpResponse response = new DefaultFullHttpResponse( HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content); //4.设置响应头信息-响应格式 response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain"); //5.设置响应头信息-响应数据长度 response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes()); //6.将构建好 response返回 ctx.writeAndFlush(response); } }}
代码说明:
浏览器发送过来的数据,被 Netty 被封装成了 HttpObject 对象,我们需要判断 HttpObject 具体所属类型是不是 HttpRequest;请求信息: 可以打印浏览器的请求信息,比如:请求地址、请求方式、请求体内容、请求头内容等;响应信息: 给浏览器响应,必须构造 HttpResponse 对象,并且可以设置响应头信息、响应体信息。
特殊说明:如果不严格按照 Http 响应格式进行输出,浏览器是无法读取服务端的响应。
4.3 测试
浏览器请求截图:
服务端打印截图:
疑惑:为什么浏览器每次请求,服务端都会打印两次呢?
原因:浏览器每次都发起两次请求,一次是业务请求,一次是浏览器的图标请求,具体如下图所示:
4.4. 静态资源过滤
我们需要把非业务请求,也就是静态资源的请求给过滤掉,避免资源的浪费,具体实现如下所示:
public class TestHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> { @Override protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { if(msg instanceof HttpRequest) { //1.打印浏览器的请求地址 System.out.println("客户端地址" + ctx.channel().remoteAddress()); //2.强制转换成HttpRequest HttpRequest httpRequest = (HttpRequest) msg; //3.获取uri, 过滤指定的资源 URI uri = new URI(httpRequest.uri()); if("/favicon.ico".equals(uri.getPath())) { System.out.println("请求了 favicon.ico, 不做响应"); return; } //4.给浏览器发送的信息,封装成ByteBuf ByteBuf content = Unpooled.copiedBuffer("hello world", CharsetUtil.UTF_8); //5.构造一个http的相应,即 httpresponse FullHttpResponse response = new DefaultFullHttpResponse( HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content); //6.设置响应头信息-响应格式 response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain"); //7.设置响应头信息-响应数据长度 response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes()); //8.将构建好 response返回 ctx.writeAndFlush(response); } }}
代码说明:
需要获取浏览器请求的 uri,并且手工判断 uri 是否等于 /favicon.ico,如果是则不往下处理;同时我们可以判断是否是 js、css、img 等资源文件。
5. 小结
本节主要是了解了 Netty 如何开发一个 Web 服务器,并且和浏览器进行通信,需要注意的地方有几点,具体如下:
格式要求,无论是解码和编码都需要严格按照 Http 协议格式要求,否则给浏览器响应数据时,浏览器不能识别;可以跟进 Http 格式,获取和设置相关信息,比如:请求 IP 地址、请求 uri 地址、请求方式、请求头内容、请求体内容等;响应头、响应体等;静态资源的过滤,一般情况下需要过滤掉,否则消耗服务器资源。
标签: #netty接收http请求