zoukankan      html  css  js  c++  java
  • 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 类作为请求,但是该类中没有获取消息体的方法,获取消息体的类为HttpContentLastHttpContent,这样获取请求和消息体则相当不对不方便。
    在查阅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

  • 相关阅读:
    使用putty上传文件到linux系统
    常用网页背景颜色
    如果你在Windows下用putty来远程连接Linux发现乱码请用下面的方法解决:
    如何让plsql查询的数据可编辑
    oracle中not in(null)问题
    linux学习之路第三天(vim和vi使用)
    linux菜鸡学习之路
    常用正则表达式()
    JAVA WEB 用servlet实现分页,思路比较清晰和简单。
    linux学习之路第三天
  • 原文地址:https://www.cnblogs.com/xuwujing/p/7782702.html
Copyright © 2011-2022 走看看