• netty使用(8)基于http的JSON传输


    1.注意本文使用的是PUT方法发送一个json对象,然后客户端接收一个json对象。

    因此使用一个C#的http工具。测试Http的POST方法的小工具 ,C#一个http 调试类httpHelper类 

    HttpClient的学习

    https://www.cnblogs.com/ITtangtang/p/3968093.html#a4

     测试效果如下:

    原理可参考netty 对http协议解析原理

    说明:HttpSeverCodec解码器可能会把一个Http请求解析成多个消息对象,导致HealthServerHandler中的channelRead 调用多次,

    HttpObjectAggregator将多个消息转化成一个HttpFullRequest ,详见文章

    package com.health;
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.Channel;
    import io.netty.channel.ChannelOption;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.handler.logging.LogLevel;
    import io.netty.handler.logging.LoggingHandler;
    import io.netty.handler.ssl.SslContext;
    import io.netty.handler.ssl.SslContextBuilder;
    import io.netty.handler.ssl.util.SelfSignedCertificate;
    
    
    /**
     * 服务的主入口
     * @author superzhan
     *
     */
    public final class MainServer {
    
        /*是否使用https协议*/
        static final boolean SSL = System.getProperty("ssl") != null;
        static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "6789"));
    
        public static void main(String[] args) throws Exception {
            // Configure SSL.
            final SslContext sslCtx;
            if (SSL) {
                SelfSignedCertificate ssc = new SelfSignedCertificate();
                sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
            } else {
                sslCtx = null;
            }
    
            // Configure the server.
            EventLoopGroup bossGroup = new NioEventLoopGroup(1);
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            try {
                ServerBootstrap b = new ServerBootstrap();
                b.option(ChannelOption.SO_BACKLOG, 1024);
                b.group(bossGroup, workerGroup)
                 .channel(NioServerSocketChannel.class)
                 .handler(new LoggingHandler(LogLevel.INFO))
                 .childHandler(new ServerInitializer(sslCtx));
    
                Channel ch = b.bind(PORT).sync().channel();
    
                System.err.println("Open your web browser and navigate to " +
                        (SSL? "https" : "http") + "://127.0.0.1:" + PORT + '/');
    
                ch.closeFuture().sync();
            } finally {
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        }
    }
    MainServer
    package com.health;
    
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelPipeline;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.handler.codec.http.HttpObjectAggregator;
    import io.netty.handler.codec.http.HttpServerCodec;
    import io.netty.handler.ssl.SslContext;
    
    public class ServerInitializer extends ChannelInitializer<SocketChannel> {
    
        private final SslContext sslCtx;
    
        public ServerInitializer(SslContext sslCtx) {
            this.sslCtx = sslCtx;
        }
    
        @Override
        public void initChannel(SocketChannel ch) {
            ChannelPipeline p = ch.pipeline();
            if (sslCtx != null) {
                p.addLast(sslCtx.newHandler(ch.alloc()));
            }
            p.addLast(new HttpServerCodec());/*HTTP 服务的解码器*/
            p.addLast(new HttpObjectAggregator(2048));/*HTTP 消息的合并处理*/
            p.addLast(new HealthServerHandler()); /*自己写的服务器逻辑处理*/
        }
    }
    ServerInitializer
    package com.health;
    
    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.HttpMethod;
    import io.netty.handler.codec.http.HttpUtil;
    import io.netty.util.AsciiString;
    import io.netty.util.CharsetUtil;
    
    import static io.netty.handler.codec.http.HttpResponseStatus.*;
    import static io.netty.handler.codec.http.HttpVersion.*;
    
    
    
    import org.json.JSONObject;
    
    public class HealthServerHandler extends ChannelInboundHandlerAdapter {
    
        private static final AsciiString CONTENT_TYPE = new AsciiString("Content-Type");
        private static final AsciiString CONTENT_LENGTH = new AsciiString("Content-Length");
        private static final AsciiString CONNECTION = new AsciiString("Connection");
        private static final AsciiString KEEP_ALIVE = new AsciiString("keep-alive");
    
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) {
            ctx.flush();
        }
    
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
    
            if (msg instanceof FullHttpRequest) {
                FullHttpRequest req = (FullHttpRequest) msg;//客户端的请求对象
                JSONObject responseJson = new JSONObject();//新建一个返回消息的Json对象
    
                //把客户端的请求数据格式化为Json对象
                JSONObject requestJson = null;
                try{
                   requestJson = new JSONObject(parseJosnRequest(req));
                }catch(Exception e)
                {
                    ResponseJson(ctx,req,new String("error json"));
                    return;
                }
    
                String uri = req.uri();//获取客户端的URL
    
                //根据不同的请求API做不同的处理(路由分发),只处理POST方法
                if (req.method() == HttpMethod.POST) {
                    if(req.uri().equals("/bmi"))
                    { 
                        //计算体重质量指数
                        double height =0.01* requestJson.getDouble("height");
                        double weight =requestJson.getDouble("weight");
                        double bmi =weight/(height*height);
                        bmi =((int)(bmi*100))/100.0;
                        responseJson.put("bmi", bmi +"");
    
                    }else if(req.uri().equals("/bmr"))
                    {
                        //计算基础代谢率
                        boolean isBoy = requestJson.getBoolean("isBoy");
                        double height = requestJson.getDouble("height");
                        double weight = requestJson.getDouble("weight");
                        int age = requestJson.getInt("age");
                        double bmr=0;
                        if(isBoy)
                        {
                            //66 + ( 13.7 x 体重kg ) + ( 5 x 身高cm ) - ( 6.8 x 年龄years )
                            bmr = 66+(13.7*weight) +(5*height) -(6.8*age);
                            System.out.println("yes boy");
                        }else
                        {
                            //655 + ( 9.6 x 体重kg ) + ( 1.8 x 身高cm ) - ( 4.7 x 年龄years )
                            bmr =655 +(9.6*weight) +1.8*height -4.7*age;
                            System.out.println("yes girl");
                        }
    
                        bmr =((int)(bmr*100))/100.0;
                        responseJson.put("bmr", bmr+"");
                    }else {
                        //错误处理
                        responseJson.put("error", "404 Not Find");
                    }
    
                } else {
                    //错误处理
                    responseJson.put("error", "404 Not Find");
                }
    
                //向客户端发送结果
                ResponseJson(ctx,req,responseJson.toString());
            }
        }
    
        /**
         * 响应HTTP的请求
         * @param ctx
         * @param req
         * @param jsonStr
         */
        private void ResponseJson(ChannelHandlerContext ctx, FullHttpRequest req ,String jsonStr)
        {
    
            boolean keepAlive = HttpUtil.isKeepAlive(req);
            byte[] jsonByteByte = jsonStr.getBytes();
            System.out.println("json byte NO. is "+jsonByteByte.length);
            FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(jsonByteByte));
            response.headers().set(CONTENT_TYPE, "text/json");
            System.out.println("conten byte NO. is "+response.content().readableBytes());
            response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());
    
            if (!keepAlive) {
                ctx.write(response).addListener(ChannelFutureListener.CLOSE);
            } else {
                response.headers().set(CONNECTION, KEEP_ALIVE);
                ctx.write(response);
            }
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            ctx.close();
        }
    
        /**
         * 获取请求的内容
         * @param request
         * @return
         */
        private String parseJosnRequest(FullHttpRequest request) {
            ByteBuf jsonBuf = request.content();
            String jsonStr = jsonBuf.toString(CharsetUtil.UTF_8);
            return jsonStr;
        }
    }
    HealthServerHandler

     本代码除了netty之外,使用了org.json库,下载地址

    本代码中对json对象做个有效性判定,非法json会返回一个errorjson信息。

    可以通过JSONObject中的isNULL("xxx“)判定key是否存在。

    使用文章: 文章1文章2,

    https://www.cnblogs.com/cfas/p/5813209.html

  • 相关阅读:
    1136 A Delayed Palindrome (algorithm reverse(ans.begin,ans.end))
    1141 PAT Ranking of Institutions PAT甲级
    最近点对 (迭代器访问数据)
    1146 Topological Order PAT 甲级
    1151 1151 LCA in a Binary Tree PAT 甲级
    jQuery的基本使用
    案例:移动端返回顶部效果
    移动端轮播图(原生JS写法)
    移动端特效
    本地存储
  • 原文地址:https://www.cnblogs.com/legion/p/8716464.html
Copyright © 2020-2023  润新知