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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Netty粘包拆包问题解决方案

    TCP黏包拆包 TCP是一个流协议,就是没有界限的一长串二进制数据.TCP作为传输层协议并不不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行数据包的划分,所以在业务上认为是一个完整的包,可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题. 怎么解决? • 消息定长度,传输的数据大小固定长度,例如每段的长度固定为100字节,如果不够空位补空格 • 在数据包尾部添加特殊分隔符,比如下划线,中划线等 • 将消息分为消息头和

  • java基于netty NIO的简单聊天室的实现

    一.为何要使用netty开发 由于之前已经用Java中的socket写过一版简单的聊天室,这里就不再对聊天室的具体架构进行细致的介绍了,主要关注于使用netty框架重构后带来的改变.对聊天室不了解的同学可以先看下我的博客(<JAVA简单聊天室的实现>) 本篇博客所使用的netty版本为4.1.36,完整工程已上传到Github(https://github.com/Alexlingl/Chatroom),其中lib文件夹下有相应的netty jar包和source包,自行导入即可. 1.为何要

  • Netty与Spring Boot的整合的实现

    ​ 最近有朋友向我询问一些Netty与SpringBoot整合的相关问题,这里,我就总结了一下基本整合流程,也就是说,这篇文章 ,默认大家是对netty与Spring,SpringMVC的整合是没有什么问题的.现在,就进入正题吧. Server端: 总的来说,服务端还是比较简单的,自己一共写了三个核心类.分别是 NettyServerListener:服务启动监听器 ServerChannelHandlerAdapter:通道适配器,主要用于多线程共享 RequestDispatcher:请求分

  • Spring Boot集成netty实现客户端服务端交互示例详解

    前言 Netty 是一个高性能的 NIO 网络框架,本文主要给大家介绍了关于SpringBoot集成netty实现客户端服务端交互的相关内容,下面来一起看看详细的介绍吧 看了好几天的netty实战,慢慢摸索,虽然还没有摸着很多门道,但今天还是把之前想加入到项目里的 一些想法实现了,算是有点信心了吧(讲真netty对初学者还真的不是很友好......) 首先,当然是在SpringBoot项目里添加netty的依赖了,注意不要用netty5的依赖,因为已经废弃了 <!--netty--> <

  • 在SpringBoot中整合使用Netty框架的详细教程

    Netty是一个非常优秀的Socket框架.如果需要在SpringBoot开发的app中,提供Socket服务,那么Netty是不错的选择. Netty与SpringBoot的整合,我想无非就是要整合几个地方 让netty跟springboot生命周期保持一致,同生共死 让netty能用上ioc中的Bean 让netty能读取到全局的配置 整合Netty,提供WebSocket服务 这里演示一个案例,在SpringBoot中使用Netty提供一个Websocket服务. servlet容器本身提

  • 深入浅析Netty 在 Dubbo 中是如何应用的

    众所周知,国内知名框架 Dubbo 底层使用的是 Netty作为网络通信,那么内部到底是如何使用的呢?今天我们就来一探究竟. 1. dubbo 的 Consumer 消费者如何使用 Netty 注意:此次代码使用了从 github 上 clone 的 dubbo 源码中的 dubbo-demo 例子. 代码如下: System.setProperty("java.net.preferIPv4Stack", "true"); ClassPathXmlApplicati

  • 利用Java搭建个简单的Netty通信实例教程

    前言 看过dubbo源码的同学应该都清楚,使用dubbo协议的底层通信是使用的netty进行交互,而最近看了dubbo的Netty部分后,自己写了个简单的Netty通信例子. 准备 工程截图 模块详解 rpc-common rpc-common作为各个模块都需使用的模块,工程中出现的是一些通信时请求的参数以及返回的参数,还有一些序列化的工具. rpc-client rpc-client中目前只是单单的一个NettyClient启动类. rpc-server rpc-client中目前也只是单单的

  • 使用Netty搭建服务端和客户端过程详解

    前言 前面我们介绍了网络一些基本的概念,虽然说这些很难吧,但是至少要做到理解吧.有了之前的基础,我们来正式揭开Netty这神秘的面纱就会简单很多. 服务端 public class PrintServer { public void bind(int port) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); //1 EventLoopGroup workerGroup = new NioEventLo

  • Java Netty HTTP服务实现过程解析

    超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议. 在后端开发中接触HTTP协议的比较多,目前大部分都是基于Servlet容器实现的Http服务,往往有一些核心子系统对性能的要求非常高,这个时候我们可以考虑采用NIO的网络模型来实现HTTP服务,以此提高性能和吞吐量,Netty除了开发网络应用非常方便,还内置了HTTP相关的编解码器,让用户可以很方便的开发出高性能的HTTP协议的服务,Spring Webflux默认是使用的N

  • Java Netty实现心跳机制过程解析

    netty心跳机制示例,使用Netty实现心跳机制,使用netty4,IdleStateHandler 实现.Netty心跳机制,netty心跳检测,netty,心跳 本文假设你已经了解了Netty的使用,或者至少写过netty的helloworld,知道了netty的基本使用.我们知道使用netty的时候,大多数的东西都与Handler有关,我们的业务逻辑基本都是在Handler中实现的.Netty中自带了一个IdleStateHandler 可以用来实现心跳检测. 心跳检测的逻辑 本文中我们

  • 通过Java读取xml文件内容过程解析

    这篇文章主要介绍了通过Java读取xml文件内容过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 需要下载jar包dom4j:https://dom4j.github.io/ package com.zyb.xml; import java.io.File; import java.util.Iterator; import org.dom4j.Attribute; import org.dom4j.Document; import or

  • java接口私有方法实现过程解析

    这篇文章主要介绍了java接口私有方法实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 问题描述: 我们需要抽取一个共有方法,用来解决两个默认方法之间重复代码的问题 但是这个共有方法不应该让实现类使用,应该是私有化的. 解决方案: 从java 9开始,接口当中允许定义私有方法. 1.普通私有方法,解决多个默认方法之间重复代码问题 格式: private 返回值类型方法名称(参数列表){ 方法体 } 2.静态私有方法,解决多个静态方法之

  • Java super关键字调用父类过程解析

    这篇文章主要介绍了Java super关键字调用父类过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 话不多说,直接上代码: package com.my.pac14; /** * @auther Summerday */ public class SuperTest { public static void main(String[] args) { SubClass sb = new SubClass(20); //创建子类的对象,调

  • Java获取配置文件的值过程解析

    这篇文章主要介绍了java获取配置文件的值过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 java大型项目中都会很多系统常量,比如说数据库的账号和密码,以及各种token值等,都需要统一的管理,如果零落的散布到各个类等具体的代码中的话,在后期管理上将是一场灾难,所有需要对这些变量进行统一的管理,一般都会放到web-service.properties文件中,该文件在项目中的位置如下: web-service.properties文件里的

  • Java使用split截取字符串过程解析

    这篇文章主要介绍了Java使用split截取字符串过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 作用背景:一串字符串中的信息有些是有用的有些是多余的,我们需要把多余的信息去掉 例:"11,22,33,44,55" 这串字符串中我们要取出所有非","的内容 public class test { public static void main(String[] args) { String[] all =

  • Java自定义实现equals()方法过程解析

    这篇文章主要介绍了Java自定义实现equals()方法过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 以常见的自定义Date类型为例,没有经验的朋友可能会觉得直接比较年月日即可,从而写出以下的实现 public class MyDate implements Comparable<MyDate> { private final int year; private final int month; private final int

  • Java基于final修饰数据过程解析

    这篇文章主要介绍了Java基于final修饰数据过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 final是Java中的一个重要关键字,它可以修饰数据.方法和类,本篇将从final修饰的数据角度对final做出总结. final修饰的数据代表着:永远不变.意思是,一旦你用final修饰一块数据,你之后就只能看看它,你想修改它,没门. 我们不希望改变的数据有下面两种情况: 永不改变的编译时常量. //编译时知道其值 private fin

  • Java输出Hello World完美过程解析

    1. 你会不会输出"Hello World!"? 图1 图 2 当我们学习一门编程语言的时候,我们都会先学如何输出Hello World!

随机推荐