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(); } } }

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()); /*自己寫的服務器邏輯處理*/ } }

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; } }
本代碼除了netty之外,使用了org.json庫,下載地址
本代碼中對json對象做個有效性判定,非法json會返回一個errorjson信息。
可以通過JSONObject中的isNULL("xxx“)判定key是否存在。
https://www.cnblogs.com/cfas/p/5813209.html