Netty處理HTTP請求和響應

概述

主要講述Netty處理HTTP請求和響應和需要注意的事項

Neey作爲HTTP服務器

1. 編寫服務器的啓動程序

/**
 * 服務端的啓動代碼,重點在HttpServerInitializer這個類中,這裏指定了pipeline的處理器
 */
public class HttpServer {
    private int port ;

    public HttpServer(int port){
        this.port = port;
    }

    public void start() throws Exception{
        ServerBootstrap bootstrap = new ServerBootstrap();
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup work = new NioEventLoopGroup();
        bootstrap.group(boss,work)
                .handler(new LoggingHandler(LogLevel.DEBUG))
                .channel(NioServerSocketChannel.class)
                .childHandler(new HttpServerInitializer());
        ChannelFuture f = bootstrap.bind(new InetSocketAddress(port)).sync();
        System.out.println(" server start up on port : " + port);
        f.channel().closeFuture().sync();
    }
}

2. 配置服務端的pipeline處理器

public class HttpServerInitializer extends ChannelInitializer<SocketChannel>{
    @Override
    protected void initChannel(SocketChannel channel) throws Exception {
        ChannelPipeline pipeline = channel.pipeline();
        pipeline.addLast(new HttpServerCodec());// http 編解碼
        pipeline.addLast("httpAggregator",new HttpObjectAggregator(512*1024)); // http 消息聚合器512*1024爲接收的最大contentlength
        pipeline.addLast(new HttpRequestHandler());// 請求處理器

    }
}

3. 編寫請求處理器的業務

public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
        if (is100ContinueExpected(req)) {
            // 檢測 100 Continue,是否同意接收將要發送過來的實體
            ctx.write(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.CONTINUE));
        }
        // 因爲經過HttpServerCodec處理器的處理後消息被封裝爲FullHttpRequest對象
		// 獲取請求的uri
        JsonObject json = new JsonObject();
        json.put("method", req.method().name()); // 獲取請求方法
        json.put("uri", req.uri()); // 獲取請求地址
        // 創建完整的響應對象
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK,Unpooled.copiedBuffer(json.toJsonString(), CharsetUtil.UTF_8));
       // 設置頭信息
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8");
       // 響應寫回給客戶端,並在協會後斷開這個連接
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }
}

4. 啓動服務器

public class Application {
    public static void main(String[] args) throws Exception{
        HttpServer server = new HttpServer(8081);// 8081爲啓動端口
        server.start();
    }
}

Netty作爲客戶端

1. 編寫http客戶端對象

// 客戶端對象,這裏處理服務的啓動配置和處理器配置
public class HttpClient {
	public static void start(String host,int port){
	    // 配置一個事件循環組和一個啓動器
		EventLoopGroup group = new NioEventLoopGroup();
		Bootstrap bootstrap = new Bootstrap();
		try {
			bootstrap.group(group)
					 .channel(NioSocketChannel.class)
					 .option(ChannelOption.SO_KEEPALIVE, true)
					 .handler(new ChannelInitializer<Channel>() {
						@Override
						protected void initChannel(Channel channel) throws Exception {
							channel.pipeline().addLast(new HttpClientCodec()); // http客戶端編解碼器
							channel.pipeline().addLast(new HttpObjectAggregator(65536)); // http消息聚合器
							channel.pipeline().addLast(new HttpContentDecompressor()); // 數據解壓處理器
							channel.pipeline().addLast(new HttpClientHandler()); // 業務邏輯處理器
						}
					});
			// 異步等待連接上遠程http服務器
			ChannelFuture future = bootstrap.connect(host, port).sync();
			// 等待與遠程http服務器斷開連接
			future.channel().closeFuture().sync();
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			group.shutdownGracefully();
		}
	}
	
	public static void main(String[] args) {
		start("127.0.0.1", 8081);
	}
}

2. 編寫業務邏輯處理器

public class HttpClientHandler extends ChannelInboundHandlerAdapter {
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
	    // 通斷被激活時我們發送請求到指定路徑
		URI uri = new URI("/user/get");
		FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_0, HttpMethod.GET, uri.toASCIIString());
		// FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri.toASCIIString()); // 有時候1.1發送的請求會報400錯誤
		// 添加請求頭,保持長連接
		request.headers().add(HttpHeaderNames.CONNECTION,HttpHeaderValues.KEEP_ALIVE);
		// 添加請求頭,確定請求體的長度
		request.headers().add(HttpHeaderNames.CONTENT_LENGTH,request.content().readableBytes());
		// 將請求實體寫入出站處理器
		ctx.writeAndFlush(request);
	}
	
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		if(msg instanceof FullHttpResponse){
		    // 收到了http服務器的響應
			FullHttpResponse response = (FullHttpResponse)msg;
			ByteBuf buf = response.content();
			String result = buf.toString(CharsetUtil.UTF_8);
			System.out.println("response -> "+ result);
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章