4、netty編寫http服務器、增加壓縮支持、netty編寫client、netty添加SL/TLS保護https支持

注:源代碼來自享學課堂,學習之後所做筆記,方便回顧,也給大家一個參考

目錄

1 netty編寫http服務器

1.1 主函數

1.2 ServerHandlerInit

1.3 服務端自定義BusiHandler

1.4至此,最簡單的netty編寫的服務器就成了,啓動主函數,通過瀏覽器訪問

2 服務器增加壓縮支持

2.1 修改ServerHandlerInit,添加上壓縮的handler

2.2 訪問接口,header出現了

2.3 transfer-encoding: chunked:接受壓縮請求

3 Client支持

3.1 client主函數

3.2 HttpClientInboundHandler

4 Https支持

4.1 修改server主函數

4.2 修改handler,加上構造函數,並給ptieline加上ssl支持

4.3 此時可通過https訪問


目錄

netty編寫http服務器

主函數

ServerHandlerInit

服務端自定義BusiHandler

至此,最簡單的netty編寫的服務器就成了,啓動主函數,通過瀏覽器訪問

瀏覽器訪問,返回的結果和正常調用接口是一樣的,/test是被攔截的請求

默認是正常的請求

服務器增加壓縮支持

修改ServerHandlerInit,添加上壓縮的handler

訪問接口,header出現了

transfer-encoding: chunked:接受壓縮請求

Client支持

HttpClientInboundHandler

Https支持

修改server主函數

修改handler,加上構造函數,並給ptieline加上ssl支持

此時可通過https訪問


1 netty編寫http服務器

1.1 主函數

public class HttpServer {
    public static final int port = 6789; //設置服務端端口


    public static void main(String[] args) throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();
        ServerBootstrap b = new ServerBootstrap();
        try {
            b.group(group);
            b.channel(NioServerSocketChannel.class);
            b.childHandler(new ServerHandlerInit ());
            // 服務器綁定端口監聽
            ChannelFuture f = b.bind(port).sync();
            System.out.println("服務端啓動成功,端口是:"+port);
            // 監聽服務器關閉監聽
            f.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }
}

1.2 ServerHandlerInit

public class ServerHandlerInit extends ChannelInitializer<SocketChannel> {

    @Override

    protected void initChannel(SocketChannel ch) throws Exception {

        ChannelPipeline pipeline = ch.pipeline();
        //http響應編碼,服務端,對於request是解碼,對於response是編碼
        pipeline.addLast("encode",new HttpResponseEncoder());
        //這裏我開始寫成了HttpResponseDecoder,程序一直報類型轉換異常,要注意
        pipeline.addLast("decode",new HttpRequestDecoder());
        ///將http請求聚合在一起,可以通過對象.content()來調用,HttpObject, HttpMessage, HttpContent, FullHttpMessage
        pipeline.addLast("aggre",new HttpObjectAggregator(10*1024*1024));
        //業務操作,自定義業務操作
        pipeline.addLast("busi",new BusiHandler());
    }
}

1.3 服務端自定義BusiHandler

public class BusiHandler extends ChannelInboundHandlerAdapter {
    private String result = "";

    private void send(String content, ChannelHandlerContext ctx,
                      HttpResponseStatus status) {
        //大部分瀏覽器都是1.1
        FullHttpResponse response =
                new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status,
                        Unpooled.copiedBuffer(content, CharsetUtil.UTF_8));
        response.headers().set(HttpHeaderNames.CONTENT_TYPE,
                "text/plain;charset=UTF-8");
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg)
            throws Exception {
        String result = "";
        //接收到完成的http請求
        FullHttpRequest httpRequest = (FullHttpRequest) msg;

        try {
            String path = httpRequest.uri();
            String body = httpRequest.content().toString(CharsetUtil.UTF_8);
            //get,post,delete,update
            HttpMethod method = httpRequest.method();
            if ("/test".equalsIgnoreCase(path)) {
                result = "錯誤請求:" + path;
                send(result, ctx, HttpResponseStatus.BAD_REQUEST);
                return;
            }
            if (HttpMethod.GET.equals(method)) {
                System.out.println("body:" + body);
                result = "get Response=服務器返回數據";
                send(result, ctx, HttpResponseStatus.OK);
            }

        } catch (Exception e) {
            System.out.println("處理請求失敗!");
            e.printStackTrace();
        } finally {

            httpRequest.release();
        }
    }


    /*
     * 建立連接時,返回消息
     */

    @Override
    public void channelActive(ChannelHandlerContext ctx)
            throws Exception {
        System.out.println("連接的客戶端地址:"
                + ctx.channel().remoteAddress());

    }
}

1.4至此,最簡單的netty編寫的服務器就成了,啓動主函數,通過瀏覽器訪問

瀏覽器訪問,返回的結果和正常調用接口是一樣的,/test是被攔截的請求

默認是正常的請求

 

 

2 服務器增加壓縮支持

2.1 修改ServerHandlerInit,添加上壓縮的handler

public class ServerHandlerInit extends ChannelInitializer<SocketChannel> {

    @Override

    protected void initChannel(SocketChannel ch) throws Exception {

        ChannelPipeline pipeline = ch.pipeline();
        //http響應編碼,服務端,對於request是解碼,對於response是編碼
        pipeline.addLast("encode",new HttpResponseEncoder());
        //這裏我開始寫成了HttpResponseDecoder,程序一直報類型轉換異常,要注意
        pipeline.addLast("decode",new HttpRequestDecoder());
        ///將http請求聚合在一起,可以通過對象.content()來調用,HttpObject, HttpMessage, HttpContent, FullHttpMessage
        pipeline.addLast("aggre",new HttpObjectAggregator(10*1024*1024));
        //添加壓縮支持
        pipeline.addLast("compressor",new HttpContentCompressor());
        //業務操作,自定義業務操作
        pipeline.addLast("busi",new BusiHandler());
    }
}

2.2 訪問接口,header出現了

 

2.3 transfer-encoding: chunked:接受壓縮請求

 

3 Client支持

3.1 client主函數

public class HttpClient {
    private static final boolean SSL = false;

    public void connect(String host, int port) throws Exception {
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(workerGroup);
            b.channel(NioSocketChannel.class);
            b.option(ChannelOption.SO_KEEPALIVE, true);
            b.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch)
                        throws Exception {
                    //這一句相當於下面的兩句
                    ch.pipeline().addLast(new HttpClientCodec());
//                    ch.pipeline().addLast(new HttpResponseDecoder());
//                    ch.pipeline().addLast(new HttpRequestEncoder());
                    ch.pipeline().addLast("aggre",
                            new HttpObjectAggregator(10 * 1024 * 1024));
                    ch.pipeline().addLast("decompressor", new HttpContentDecompressor());
                    ch.pipeline().addLast("busi", new HttpClientInboundHandler());
                }
            });

            // Start the client.
            ChannelFuture f = b.connect(host, port).sync();

            URI uri = new URI("/test");
            String msg = "Hello";
            DefaultFullHttpRequest request =
                    new DefaultFullHttpRequest(HttpVersion.HTTP_1_1,
                            HttpMethod.GET,
                            uri.toASCIIString(),
                           Unpooled.wrappedBuffer(msg.getBytes("UTF-8")));

            // 構建http請求
            request.headers().set(HttpHeaderNames.HOST, host);
            request.headers()
                    .set(HttpHeaderNames.CONNECTION,
                            HttpHeaderValues.KEEP_ALIVE);
            request.headers()
                    .set(HttpHeaderNames.CONTENT_LENGTH,
                            request.content().readableBytes());
            // 發送http請求
            f.channel().write(request);
            f.channel().flush();
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
        }

    }


    public static void main(String[] args) throws Exception {
        HttpClient client = new HttpClient();
        client.connect("127.0.0.1", HttpServer.port);
    }
}

3.2 HttpClientInboundHandler

public class HttpClientInboundHandler
        extends ChannelInboundHandlerAdapter {

    public void channelRead(ChannelHandlerContext ctx, Object msg)
            throws Exception {
        //開始對服務器的響應做處理
        FullHttpResponse httpResponse = (FullHttpResponse)msg;
        System.out.println(httpResponse.headers());
        ByteBuf content = httpResponse.content();
        System.out.println(content.toString(CharsetUtil.UTF_8));
        content.release();
    }
}

建議直接使用開源的apache的HttpClient

4 Https支持

4.1 修改server主函數

public static void main(String[] args) throws Exception {

    //netty爲我們提供的ssl加密,缺省
    SelfSignedCertificate ssc = new SelfSignedCertificate();
    SslContext build = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
    EventLoopGroup group = new NioEventLoopGroup();
    ServerBootstrap b = new ServerBootstrap();

    try {

        b.group(group);
        b.channel(NioServerSocketChannel.class);
        b.childHandler(new ServerHandlerInit(build));
        // 服務器綁定端口監聽
        ChannelFuture f = b.bind(port).sync();
        System.out.println("服務端啓動成功,端口是:"+port);
        // 監聽服務器關閉監聽
        f.channel().closeFuture().sync();
    } finally {
        group.shutdownGracefully();
    }
}

4.2 修改handler,加上構造函數,並給ptieline加上ssl支持

public class ServerHandlerInit extends ChannelInitializer<SocketChannel> {

    private SslContext build;
    public ServerHandlerInit(SslContext build) {
        this.build = build;
    }

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {

        ChannelPipeline pipeline = ch.pipeline();

        //啓用ssl
        pipeline.addLast(build.newHandler(ch.alloc()));

        //http響應編碼,服務端,對於request是解碼,對於response是編碼
//        pipeline.addLast(new HttpServerCodec());這一句可以替代下面的幾句
        pipeline.addLast("encode",new HttpResponseEncoder());
        //這裏我開始寫成了HttpResponseDecoder,程序一直報類型轉換異常,要注意
        pipeline.addLast("decode",new HttpRequestDecoder());
        ///將http請求聚合在一起,可以通過對象.content()來調用,HttpObject, HttpMessage, HttpContent, FullHttpMessage
        pipeline.addLast("aggre",new HttpObjectAggregator(10*1024*1024));
        //添加壓縮支持
        pipeline.addLast("compressor",new HttpContentCompressor());
        //業務操作,自定義業務操作
        pipeline.addLast("busi",new BusiHandler());
    }
}

4.3 此時可通過https訪問

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章