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

posted on 2018-04-04 11:52  legion  阅读(2627)  评论(0编辑  收藏  举报

导航