Netty 实现简单的HTTP服务

Posted 猿天地

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Netty 实现简单的HTTP服务相关的知识,希望对你有一定的参考价值。

本篇文章是Netty专题的第八篇,前面七篇文章如下:

超文本传输协议(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 {
   
   @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中获取请求的参数呢?

下面已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请求包含的信息:

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

更多技术分享请加我微信,我拉你进群进行交流:


以上是关于Netty 实现简单的HTTP服务的主要内容,如果未能解决你的问题,请参考以下文章

代码片段 - Golang 实现简单的 Web 服务器

Netty笔记

java 从零开始手写 RPC (02)-netty4 实现客户端和服务端

Java进阶:Netty实现RPC的代码

Netty整合SpringMVC,实现高效的HTTP服务请求

老王:Netty到底是个什么鬼?有没有简单的理解方式?