Java Netty HTTP服务实现过程解析
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。
在后端开发中接触HTTP协议的比较多,目前大部分都是基于Servlet容器实现的Http服务,往往有一些核心子系统对性能的要求非常高,这个时候我们可以考虑采用NIO的网络模型来实现HTTP服务,以此提高性能和吞吐量,Netty除了开发网络应用非常方便,还内置了HTTP相关的编解码器,让用户可以很方便的开发出高性能的HTTP协议的服务,Spring Webflux默认是使用的Netty。
接下来我们简单的介绍下如何使用Netty来构建一个简单的Http服务
创建一个NettyHttpServer来启动服务
public static void main(String[] args) { int port = 2222; new NettyHttpServer().run(port); } public void run(int port) { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast( new HttpResponseEncoder(), new HttpRequestDecoder(), new NettyHttpServerHandler()); } }).option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); try { ChannelFuture f = bootstrap.bind(port).sync(); f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } }
需要关注的是下面的这行代码:
ch.pipeline().addLast(
new HttpResponseEncoder(),
new HttpRequestDecoder(),
new NettyHttpServerHandler());
HttpResponseEncoder: 服务端往客户端发送数据的行为是Response,所以这边要使用HttpResponseEncoder将数据进行编码操作
HttpRequestDecoder:服务端接收到数据的行为是Request,所以要使用HttpRequestDecoder进行解码操作
NettyHttpServerHandler:自定义的数据处理类
public class NettyHttpServerHandler extends ChannelInboundHandlerAdapter {
public class NettyHttpServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { FullHttpResponse response = new DefaultFullHttpResponse( HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer("欢迎来到猿天地".getBytes("utf-8"))); response.headers().set(Names.CONTENT_TYPE, "text/plain;charset=UTF-8"); response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes()); response.headers().set(Names.CONNECTION, Values.KEEP_ALIVE); ctx.write(response); ctx.flush(); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); cause.printStackTrace(); } }
通过DefaultFullHttpResponse构建了返回的对象,设置了HTTP版本,返回的状态码,返回的内容。
返回的响应头通过response.headers().set()进行设置。
到此为止,一个简单的HTTP服务就实现好了,我们启动服务,在浏览器中输入http://localhost:2222/ 就可以看到页面中显示的内容是:欢迎来到猿天地
上面演示的是一个典型的请求响应模式,一般我们开发接口的时候通常都是需要根据请求的参数进行对应的数据返回,如何在Netty中获取请求的参数呢?
channelRead方法中的msg参数就是请求信息,通过msg可以获取到请求的所有信息,有请求头信息(包括请求的地址,GET请求的参数),请求体(POST请求的数据)。
下面已GET请求的方式来获取请求的参数信息,代码如下:
if (msg instanceof HttpRequest) { DefaultHttpRequest request = (DefaultHttpRequest) msg; System.out.println("URI:" + request.getUri()); System.err.println(msg); } if (msg instanceof HttpContent) { LastHttpContent httpContent = (LastHttpContent) msg; ByteBuf byteData = httpContent.content(); if (byteData instanceof EmptyByteBuf) { System.out.println("Content:无数据"); } else { String content = new String(ByteUtils.objectToByte(byteData)); System.out.println("Content:" + content); } }
重启服务,访问地址加上参数进行访问:http://localhost:2222/?name=yjh
可以看到控制台输出的内容就是一个完整的HTTP请求包含的信息:
URI:/?name=yjh
DefaultHttpRequest(decodeResult: success, version: HTTP/1.1)
GET /?name=yjh HTTP/1.1
Host: localhost:2222
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _ga=GA1.1.939107719.1520393952; JSESSIONID=EE205236911D5BBA145E3021DB472D90
Content:无数据
本文只是简单的介绍了如何在Netty中去实现HTTP服务,如果想要做成Spring MVC这样的框架那后面的路还很长,请求响应Netty内置了编解码器,还是有很多工作需要自己去做的。比如参数的获取,请求的路由,参数映射成对象等….
源码参考:https://github.com/yinjihuan/netty-im
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
相关文章
Spring Boot集成Swagger接口分类与各元素排序问题
这篇文章主要介绍了Spring Boot集成Swagger接口分类与各元素排序问题,首先我们需要对Swagger中的接口也就是以Controller 层作为第一级梯度进行组织的,Controller在我们实际开发中,与其他具体接口之间是存在一对多的关系,本文给大家介绍的非常详细,需要的朋友参考下吧2023-10-10SpringBoot 中 AutoConfiguration的使用方法
这篇文章主要介绍了SpringBoot 中 AutoConfiguration的使用方法,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下2019-04-04Springboot解决no main manifest attribute错误
在开发Springboot项目时,使用java -jar命令运行jar包可能出现no main manifest attribute错误,本文就来介绍一下该错误的解决方法,感兴趣的可以了解一下2024-09-09
最新评论