Netty4系列--實現簡單的Http協議
阿新 • • 發佈:2019-02-20
利用netty4來實現http的伺服器,程式碼如下:
public class ApiServer { public static void main(String[] args) { int port = 8089; if (args != null && args.length > 0) { try { port = Integer.parseInt(args[0]); } catch (Exception e) { } } try { new ApiServer().bind(port); System.out.println(String.format("start %s", port)); } catch (Exception e) { // TODO Auto-generated catch block System.out.println(e.getMessage()); } } public void bind(int port) throws Exception { NioEventLoopGroup bossGroup = new NioEventLoopGroup(1); NioEventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap boot = new ServerBootstrap(); boot.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel ch) throws Exception { // server端是接收 ,所以這裡是httprequest解碼 ch.pipeline().addLast(new HttpRequestDecoder()); // 訊息合併+最大2M,防止半包問題 ch.pipeline().addLast("http-aggregator", new HttpObjectAggregator(2 * 1024 * 1024)); //server端會返回respose 所以這裡是進行編碼 ch.pipeline().addLast(new HttpResponseEncoder()); //處理器 ch.pipeline().addLast(new HttpMessageHandler()); } }); //繫結埠,同步等待成功 ChannelFuture f = boot.bind(port).sync(); System.out.println("yes bind"+port); //等待服務端監聽埠關閉; f.channel().closeFuture().sync(); } catch (Exception e) { System.out.println(e.getMessage()); }finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }
由於這裡是實現server端的,所以對於接收的請求需要進行解碼,另外在進行接收訊息的時候為了避免半包的問題需要使用了讀取訊息的長度。最後這裡會進行輸出的響應,因此這裡是使用了ReponseEncode。
在netty 4中,實現訊息的處理是繼承ChannelInboundHandlerAdapter 類,程式碼如下:
在這裡通過去判斷request的方法型別來去獲取引數,最後是通過FullHttpResponse來進行響應頭的輸出。public class HttpMessageHandler extends ChannelInboundHandlerAdapter { private static Log LOG=LogFactory.getLog(HttpMessageHandler.class); //進行訊息的接收 @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //在這裡進行讀取內容 if(msg instanceof HttpRequest){ HttpRequest request=(HttpRequest)msg; String url =request.uri(); //判斷方法 Map<String, String> paramMap=new HashMap<String,String>(); if(request.method().name().equals(HttpMethod.GET.name())){ //get 請求 //獲取引數 QueryStringDecoder parmDecoder= new QueryStringDecoder(url); Map<String,List<String>> params=parmDecoder.parameters(); if(!params.isEmpty()){ params.forEach((k,v)->{ v.forEach(item->{ paramMap.put(k, item); System.out.println(String.format("get %s:%s", k,item)); }); }); } String res = "I am OK"; write(ctx, res, null); //獲取get的引數 }else if(request.method().name().equals(HttpMethod.POST.name())){ //post 請求 HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(request); decoder.offer((HttpContent)request); List<InterfaceHttpData> parmList = decoder.getBodyHttpDatas(); for (InterfaceHttpData parm : parmList) { Attribute data = (Attribute) parm; paramMap.put(data.getName(), data.getValue()); System.out.println(String.format("post %s_%s", data.getName(),data.getValue())); } String res = "I am OK"; write(ctx, res, null); } }else{ //進行返回404 String res = "404"; write(ctx, res, null); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { super.exceptionCaught(ctx, cause); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { super.channelReadComplete(ctx); } //寫入,傳送回客戶端 private void write(ChannelHandlerContext ctx,String res,String contentType) { byte[] bytes=null; try { bytes=res.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(bytes)); if(contentType!=null){ response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain"); }else{ response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain"); } response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, response.content().readableBytes()); ctx.write(response); ctx.flush(); } }