天天看點

netty4 linux 部署,netty4.x學習四http伺服器的搭建

通過學習了解到netty可以像tomcat一樣搭建一個httpServer伺服器,這裡簡單的實作一下。

首先,我們介紹一下httpRequest

認識Http請求

在動手寫Netty架構之前,我們先要了解http請求的組成,如下圖:

netty4 linux 部署,netty4.x學習四http伺服器的搭建

image.png

HTTP Request 第一部分是包含的頭資訊

HttpContent 裡面包含的是資料,可以後續有多個 HttpContent 部分

LastHttpContent 标記是 HTTP request 的結束,同時可能包含頭的尾部資訊

完整的 HTTP request,由1,2,3組成

netty4 linux 部署,netty4.x學習四http伺服器的搭建

image.png

HTTP response 第一部分是包含的頭資訊

HttpContent 裡面包含的是資料,可以後續有多個 HttpContent 部分

LastHttpContent 标記是 HTTP response 的結束,同時可能包含頭的尾部資訊

完整的 HTTP response,由1,2,3組成

從request的介紹我們可以看出來,一次http請求并不是通過一次對話完成的,他中間可能有很次的連接配接。netty每一次對話都會建立一個channel,并且一個ChannelInboundHandler一般是不會同時去處理多個Channel的。

如何在一個Channel裡面處理一次完整的Http請求?這就要用到我們上圖提到的FullHttpRequest,我們隻需要在使用netty處理channel的時候,隻處理消息是FullHttpRequest的Channel,這樣我們就能在一個ChannelHandler中處理一個完整的Http請求了。

ph.addLast("aggregator", new HttpObjectAggregator(10*1024*1024));//把單個http請求轉為FullHttpReuest或FullHttpResponse

開始搭建

Server

public class NettyServer {

private static final int port = 6789; //設定服務端端口

private static EventLoopGroup group = new NioEventLoopGroup(); // 通過nio方式來接收連接配接和處理連接配接

private static ServerBootstrap b = new 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("服務端啟動成功...");

// 監聽伺服器關閉監聽

f.channel().closeFuture().sync();

} finally {

group.shutdownGracefully(); 關閉EventLoopGroup,釋放掉所有資源包括建立的線程

}

}

}

ChannelInitializer

public class NettyServerFilter extends ChannelInitializer {

@Override

protected void initChannel(SocketChannel ch) throws Exception {

ChannelPipeline ph = ch.pipeline();

ph.addLast("encoder",new HttpResponseEncoder());

ph.addLast("decoder",new HttpRequestDecoder());

ph.addLast("aggregator", new HttpObjectAggregator(10*1024*1024));//把單個http請求轉為FullHttpReuest或FullHttpResponse

ph.addLast("handler", new NettyServerHandler());// 服務端業務邏輯

}

}

ChannelInboundHandlerAdapter

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

}

}

private String getBody(FullHttpRequest request){

ByteBuf buf = request.content();

return buf.toString(CharsetUtil.UTF_8);

}

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

}

}

最終效果

netty4 linux 部署,netty4.x學習四http伺服器的搭建

image.png

netty4 linux 部署,netty4.x學習四http伺服器的搭建

項目位址 https://github.com/DespairYoke/netty/tree/master/netty-httpserver