Netty4 学习笔记之四: Netty HTTP服务的实现
前言
目前主流的JAVA web 的HTTP服务主要是 springMVC和Struts2,更早的有JSP/servlet。
在学习Netty的时候,发现Netty 也可以作HTTP服务,于是便将此整理一篇博文,分享给大家。
开发准备
添加配置
将Netty作为HTTP服务,需要在过滤器中添加HttpRequest之类的配置,如:
ph.addLast("encoder",new HttpResponseEncoder());
ph.addLast("decoder",new HttpRequestDecoder());
ph.addLast("aggregator", new HttpObjectAggregator(10*1024*1024));
基本配置和之前的客户端和服务端通信Demo几乎一样,就是在业务处理器中略微的修改下业务逻辑处理就可以了。
HTTP GET请求测试
那么进行测试。
首先启动Netty服务,然后使用HTTP GET 方式测试(直接在浏览器上输入http://localhost:6789/test)
结果如下:
HTTP服务准备
一般来说,使用HttpRequest 类作为请求,但是该类中没有获取消息体的方法,获取消息体的类为HttpContent 或LastHttpContent,这样获取请求和消息体则相当不对不方便。
在查阅Netty相关资料后,发现这样一个请求类,可以完成上述所提的要求。这个类就是FullHttpRequest。
查看该类源码,可以发现该类继承HttpRequest, FullHttpMessage,而FullHttpMessage又继承LastHttpContent, 而LastHttpContent又继承HttpContent,所以该类可以实现上述要求。
源码示例图:
那么代码修改如下:
FullHttpRequest httpRequest = (FullHttpRequest)msg;
String path=httpRequest.uri(); //获取路径
String body = getBody(httpRequest); //获取参数
HttpMethod method=httpRequest.method();//获取请求方法
然后测试POST、PUT和DELETE请求并使用json格式传输。
我们可以通过postman等工具来直接调用,就不用写相关请求代码了
可以看见,Netty 作为HTTP服务可以接受基本的请求。
完整的代码如下:
服务端:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
*
* Title: NettyServer
* Description: Netty服务端 Http测试
* Version:1.0.0
* @author pancm
* @date 2017年10月26日
*/
public class NettyServer {
private static final int port = 6789; //设置服务端端口
private static EventLoopGroup group = new NioEventLoopGroup(); // 通过nio方式来接收连接和处理连接
private static ServerBootstrap b = new ServerBootstrap();
/**
* Netty创建全部都是实现自AbstractBootstrap。
* 客户端的是Bootstrap,服务端的则是 ServerBootstrap。
**/
public static void main(String[] args) throws InterruptedException {
try {
b.group(group);
b.channel(NioServerSocketChannel.class);
b.childHandler(new NettyServerFilter()); //设置过滤器
// 服务器绑定端口监听
ChannelFuture f = b.bind(port).sync();
System.out.println("服务端启动成功,端口是:"+port);
// 监听服务器关闭监听
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully(); //关闭EventLoopGroup,释放掉所有资源包括创建的线程
}
}
}
服务端过滤器:
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
/**
*
* Title: NettyServerFilter
* Description: Netty 服务端过滤器
* Version:1.0.0
* @author pancm
* @date 2017年10月26日
*/
public class NettyServerFilter extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline ph = ch.pipeline();
//处理http服务的关键handler
ph.addLast("encoder",new HttpResponseEncoder());
ph.addLast("decoder",new HttpRequestDecoder());
ph.addLast("aggregator", new HttpObjectAggregator(10*1024*1024));
ph.addLast("handler", new NettyServerHandler());// 服务端业务逻辑
}
}
服务端业务逻辑
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.CharsetUtil;
import java.net.InetAddress;
/**
*
* Title: NettyServerHandler
* Description: 服务端业务逻辑
* Version:1.0.0
* @author pancm
* @date 2017年10月26日
*/
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
private String result="";
/*
* 收到消息时,返回信息
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if(! (msg instanceof FullHttpRequest)){
result="未知请求!";
send(ctx,result,HttpResponseStatus.BAD_REQUEST);
return;
}
FullHttpRequest httpRequest = (FullHttpRequest)msg;
try{
String path=httpRequest.uri(); //获取路径
String body = getBody(httpRequest); //获取参数
HttpMethod method=httpRequest.method();//获取请求方法
//如果不是这个路径,就直接返回错误
if(!"/test".equalsIgnoreCase(path)){
result="非法请求!";
send(ctx,result,HttpResponseStatus.BAD_REQUEST);
return;
}
System.out.println("接收到:"+method+" 请求");
//如果是GET请求
if(HttpMethod.GET.equals(method)){
//接受到的消息,做业务逻辑处理...
System.out.println("body:"+body);
result="GET请求";
send(ctx,result,HttpResponseStatus.OK);
return;
}
//如果是POST请求
if(HttpMethod.POST.equals(method)){
//接受到的消息,做业务逻辑处理...
System.out.println("body:"+body);
result="POST请求";
send(ctx,result,HttpResponseStatus.OK);
return;
}
//如果是PUT请求
if(HttpMethod.PUT.equals(method)){
//接受到的消息,做业务逻辑处理...
System.out.println("body:"+body);
result="PUT请求";
send(ctx,result,HttpResponseStatus.OK);
return;
}
//如果是DELETE请求
if(HttpMethod.DELETE.equals(method)){
//接受到的消息,做业务逻辑处理...
System.out.println("body:"+body);
result="DELETE请求";
send(ctx,result,HttpResponseStatus.OK);
return;
}
}catch(Exception e){
System.out.println("处理请求失败!");
e.printStackTrace();
}finally{
//释放请求
httpRequest.release();
}
}
/**
* 获取body参数
* @param request
* @return
*/
private String getBody(FullHttpRequest request){
ByteBuf buf = request.content();
return buf.toString(CharsetUtil.UTF_8);
}
/**
* 发送的返回值
* @param ctx 返回
* @param context 消息
* @param status 状态
*/
private void send(ChannelHandlerContext ctx, String context,HttpResponseStatus status) {
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(context, CharsetUtil.UTF_8));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
/*
* 建立连接时,返回消息
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("连接的客户端地址:" + ctx.channel().remoteAddress());
ctx.writeAndFlush("客户端"+ InetAddress.getLocalHost().getHostName() + "成功与服务端建立连接! ");
super.channelActive(ctx);
}
}
结语
那么Netty HTTP 服务的相关测试就到这了,如果有什么疑问,欢迎讨论!
该项目我放在github上了,有兴趣的可以看看!https://github.com/xuwujing/Netty
Netty4 学习笔记之四: Netty HTTP服务的实现的更多相关文章
- Netty4 学习笔记之一:客户端与服务端通信 demo
前言 因为以前在项目中使用过Mina框架,感受到了该框架的强大之处.于是在业余时间也学习了一下Netty.因为Netty的主要版本是Netty3和Netty4(Netty5已经被取消了),所以我就直接 ...
- Oracle学习笔记之四sp1,Oracle 11g的常用函数
从Oracle学习笔记之四,SQL语言入门中摘出来的,独立成一章节 3.1 字符类函数 ASCII(c)和CHR(i) 分别用于返回一个字符的ASCII码和返回给定ASCII值所对应的字符. C ...
- Netty学习笔记(二)——netty组件及其用法
1.Netty是 一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端. 原生NIO存在的问题 1) NIO的类库和API繁杂,使用麻烦:需要熟练掌握Selector.Se ...
- 多线程编程学习笔记——异步调用WCF服务
接上文 多线程编程学习笔记——使用异步IO 接上文 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端 接上文 多线程编程学习笔记——异步操作数据库 本示例描述了如何创建一个WCF服务,并宿主 ...
- Binder学习笔记(九)—— 服务端如何响应Test()请求 ?
从服务端代码出发,TestServer.cpp int main() { sp < ProcessState > proc(ProcessState::self()); sp < I ...
- Django 学习笔记之四 QuerySet常用方法
QuerySet是一个可遍历结构,它本质上是一个给定的模型的对象列表,是有序的. 1.建立模型: 2.数据文件(test.txt) 3.文件数据入库(默认的sqlite3) 入库之前执行 数据库同步命 ...
- Netty4 学习笔记之三:粘包和拆包
前言 在上一篇Netty 心跳 demo 中,了解了Netty中的客户端和服务端之间的心跳.这篇就来讲讲Netty中的粘包和拆包以及相应的处理. 名词解释 粘包: 会将消息粘粘起来发送.类似吃米饭,一 ...
- 【Visual C++】游戏编程学习笔记之四:透明动画实现
本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44224963 作者:ZeeCod ...
- Oracle学习笔记之四,SQL语言入门
1. SQL语言概述 1.1 SQL语言特点 集合性,SQL可以的高层的数据结构上进行工作,工作时不是单条地处理记录,而对数据进行成组的处理. 统一性,操作任务主要包括:查询数据:插入.修改和删除数据 ...
随机推荐
- [翻译]欢迎来到 C# 7.1
[翻译]欢迎来到 C# 7.1 原文: Welcome to C# 7.1 在 C# 中,我们一直倾向于主要版本:捆绑了很多功能,并且不太频繁地发布.当我们谈到 C#6.0时,我们甚至还经常忽略掉后面 ...
- 【每天半小时学框架】——React.js的模板语法与组件概念
[重点提前说:组件化与虚拟DOM是React.js的核心理念!] 先抛出一个论题:在React.js中,JSX语法提倡将 HTML 和 CSS 全都写入到JavaScrip ...
- js实现前端下载文件
在前端下载文本格式的文件时,可采用下面的方式: (1)创建基于文件内容的Blob对象: (2)通过URL上的createObjectURL方法,将blob对象转换成一个能被浏览器解析的文件地址. (3 ...
- JSOUP教程,JSOUP 乱码处理,JSOUP生僻字乱码解决方案
JSOUP乱码情况产生 这几天我用 JSOUP 多线程的方式,爬取了200 多万数据,数据为各地的地名相关.结果有小部分数据,不到 1 万乱码.我先检查了我的编码为UTF-8 ,觉得应该没有问题.代码 ...
- 外键删除(T-SQL Drop Foreign Key)
列出某张表相关的 FK Name select distinct name from sys.objects where object_id in ( select fk.constraint_o ...
- sublime 集成git插件,及git常用命令
以前用了很久的totoiseSVN,显然不够高大上,开发界的版本装x利器还得是git.然而git的命令行对没怎么用过linux的人可能觉得还不如用gitGUI,可是当你知道sublime可以集成git ...
- 网页静态化技术Freemarker的详细介绍
网页静态化技术Freemarker 一.Freemarker的基本介绍 1.1为什么要使用网页静态化技术 网页静态化解决方案在实际开发中运用比较多,例如新闻网站,门户网站中的新闻频道或者是文章类的频道 ...
- 解决ajax的parsererror错误的终极办法(后台传给前台的数据json问题)
解决ajax的parsererror错误的终极办法(后台传给前台的数据json问题) 出现这个问题的原因是因为后台传给前台的数据出现了问题,ajax对于json的格式特别的严格 下面是会出现这个问题的 ...
- C++静态库与动态库(转)
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA0cAAAC6CAIAAADqPKGOAAAgAElEQVR4nO2dy5WrOhREFYgjcAQ9Iw
- [转]Oracle High Water Level高水位分析
PLSQL_性能优化系列14_Oracle High Water Level高水位分析 http://www.cnblogs.com/eastsea/p/4005814.html 一.摘要 PLSQL ...