java netty http https pool 例子

                                 java netty http https pool 例子

1.废话不多说,写出这个netty 的例子还是花了我不少时间的,,期间遇到各种问题折腾了蛮久的。
netty 的核心组件我这里就不详解了,,有很多讲的很好的文章大家可以在百度搜索下

首先上一个netty 最简单的例子

boot = new Bootstrap();

// 绑定管理分组
boot.group(new NioEventLoopGroup());

// 这里是设置Channel 类型,一般用 NioSocketChannel  比较多,毕竟netty异步玩的6
boot.channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true);;

boot.handler(new ChannelInitializer<NioSocketChannel>() {

        @Override
        protected void initChannel(NioSocketChannel arg0) throws Exception {

            // 将多个消息转为一个full
            arg0.pipeline().addLast(new HttpObjectAggregator(65536));

            // 添加请求编码
            arg0.pipeline().addLast(new HttpRequestEncoder());

            // 添加请求解码
            arg0.pipeline().addLast(new HttpResponseDecoder());

        }
    });


其实写代码的时候最重要的是   ChannelHandler  所有的数据都是经过 ChannelHandler  处理的, 
pipeline 的作用是将所有的 ChannelHandler 连在一起形成一个链表
我们现在抛开netty的io 管理 不谈,就只管pipeline  
比如 现在有一个http请求
“` ——————————– 分割线————- HTTP/1.1 200 OK Cache-Control: private Connection: Keep-Alive Content-Encoding: gzip Content-Length: 267 Content-Type: text/javascript; charset=gbk Date: Thu, 31 Aug 2017 15:01:56 GMT Expires: Thu, 31 Aug 2017 16:01:56 GMT Server: suggestion.baidu.zbb.df ———- 下面是http响应body jQuery110205708391915849484_1504191642334({“q”:”hah”,”p”:false,”bs”:”“,”csor”:”3”,”status”:0,”g”:[ { “q”: “¹þ¹þmx”, “t”: “n”, “st”: { “q”: “¹þ¹þmx”, “new”: 0 } }, { “q”: “¹þ¹þÉÙ¶ù”, “t”: “n”, “st”: { “q”

“¹þ¹þÉÙ¶ù”, “new”: 0 } }, { “q”: “¹þ¹þ”, “t”: “n”, “st”: { “q”: “¹þ¹þ”, “new”: 0 } }, { “q”: “haha”
, “t”: “n”, “st”: { “q”: “haha”, “new”: 0 } }, { “q”: “¹þ¹þ¶¯Âþ”, “t”: “n”, “st”: { “q”: “¹þ¹þ¶¯Âþ”,
“new”: 0 } }, { “q”: “¹þ¹þ¹þ”, “t”: “n”, “st”: { “q”: “¹þ¹þ¹þ”, “new”: 0 } }, { “q”: “¹þ¹þ¾µ”, “t”:
“n”, “st”: { “q”: “¹þ¹þ¾µ”, “new”: 0 } }, { “q”: “hahaha”, “t”: “n”, “st”: { “q”: “hahaha”, “new”: 0
} }, { “q”: “¹þ¹þ¹þ¹þàÔ, “t”: “n”, “st”: { “q”: “¹þ¹þ¹þ¹þàÔ, “new”: 0 } }, { “q”: “¹þ¹þ¹þ±íÇé°ü”,
“t”: “n”, “st”: { “q”: “¹þ¹þ¹þ±íÇé°ü”, “new”: 0 } } ],”s”:[“¹þ¹þmx”,”¹þ¹þÉÙ¶ù”,”¹þ¹þ”,”haha”,”¹þ¹þ¶
¯Âþ”,”¹þ¹þ¹þ”,”¹þ¹þ¾µ”,”hahaha”,”¹þ¹þ¹þ¹þàÔ,”¹þ¹þ¹þ±íÇé°ü”]});

你好,我是http请求body

“`——————————– 分割线————-
上面是一个完整的http请求,我们在使用时一般只需要body 那么问题来了,我们这里用的io 是 NioSocketChannel 它其实是一个tcp 连接,未经处理返回的是一个byte数组,我们不能直接使用,这个时候就需要用到 ChannelHandler 来处理了!因为是服务端返回的数据我们需要解码,这里用的是 HttpResponseDecoder 来处理。HttpResponseDecoder 能将它解成handler 和 body两部分,这样我们就可以像httpclient一样来使用了!
同样我们发起http请求也需要 ChannelHandler 来帮我们将请求的内容进行一个组装 (HttpRequestEncoder)这样我们基本的http请求和http响应就处理完成了,

但是我们现在还没有对响应的数据进行接收。同样我们接收数据也需要用到ChannelHandler 但是我们没必要直接去实现ChannelHandler 接口 我们可以继承 ChannelInboundHandlerAdapter 在ChannelInboundHandlerAdapter 中帮我们做了很多处理工作,我们只需要关心基本的接收数据就可以了

—————————- 分割线

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

    if (msg instanceof HttpResponse) {

        HttpResponse response = (HttpResponse) msg;

        List<Map.Entry<String, String>>  headresList =  response.headers().entries();

        for (Map.Entry<String, String>  h : headresList){
            result.handles.put(h.getKey(), h.getValue());
        }



    }
    if (msg instanceof HttpContent) {

        HttpContent content = (HttpContent) msg;
        ByteBuf buf = content.content();

        int bodyLength = ( result.body != null ?  result.body.length : 0);

        byte[] tempBs = new byte[buf.readableBytes() + bodyLength];

        if (tempBs.length != bodyLength){

            if ( bodyLength > 0){
                System.arraycopy(result.body , 0 , tempBs , 0 , bodyLength);
            }

            buf.readBytes(tempBs ,bodyLength , buf.readableBytes() );
            result.body = tempBs;
        }

        // 如果是最后一个,,释放客户端
        if(msg instanceof LastHttpContent){
            result.completeBody();
            client.release(ctx.channel(), uri);
        }


    }
}

————————– 分割线

其中 channelRead 是用来接收数据的,但是channelRead可能会被调用多次,比如 http响应数据至少会被调用两次,第一次是 HttpResponse里面主要包含响应头
第二次是 HttpContent 响应数据 ,有一点要注意 HttpContent 可能分为几次返回 我们可以使用 LastHttpContent 来判断是否是最后一次
netty中响应数据是异步的。我们需要用异步的方式处理

下面是我们使用时简单处理逻辑图

简单流程图](https://img-blog.csdn.net/20170831233615744?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdXBkYXRlXzAwMQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

总之一点,netty中所有的操作都是异步的,不管是 创建链接,发送数据,接收数据都是会异步放在线程池处理,这样就可以使用很少的线程资源来管理大量io连接

具体代码请看 src\xiaoa\java\netty\HttpClientUtils.java (https://git.oschina.net/xiaoa1/java1.7Dome/tree/master/src/xiaoa/java/netty
一切都以 HttpClientUtils.java 为开头

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的 Java Netty 实现的 HTTP/HTTPS 代理服务代码示例: ```java import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.DefaultHttpRequest; import io.netty.handler.codec.http.HttpClientCodec; import io.netty.handler.codec.http.HttpContent; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpObject; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslHandler; import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import io.netty.util.CharsetUtil; import javax.net.ssl.SSLEngine; import java.net.InetSocketAddress; import java.util.HashMap; import java.util.Map; public class HttpsProxyServer { private final int port; public HttpsProxyServer(int port) { this.port = port; } public void start() throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .localAddress(new InetSocketAddress(port)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new HttpServerCodec()); ch.pipeline().addLast(new HttpsProxyServerHandler()); } }) .childOption(ChannelOption.AUTO_READ, false) .bind().sync().channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("Usage: " + HttpsProxyServer.class.getSimpleName() + " <port>"); return; } int port = Integer.parseInt(args[0]); new HttpsProxyServer(port).start(); } private static final class HttpsProxyServerHandler extends SimpleChannelInboundHandler<HttpObject> { private Channel clientChannel; private Channel serverChannel; private SSLEngine sslEngine; private boolean isHttps; private final Map<String, String> headers = new HashMap<>(); @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { clientChannel = ctx.channel(); } @Override public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { if (msg instanceof DefaultHttpRequest) { DefaultHttpRequest request = (DefaultHttpRequest) msg; String requestUri = request.getUri(); isHttps = requestUri.startsWith("https://"); String[] hostParts = HttpHeaders.getHost(request).split(":"); String host = hostParts[0]; int port = isHttps ? 443 : (hostParts.length > 1 ? Integer.parseInt(hostParts[1]) : 80); Bootstrap b = new Bootstrap(); b.group(clientChannel.eventLoop()) .channel(NioSocketChannel.class) .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { if (isHttps) { sslEngine = SslContextBuilder.forClient() .trustManager(InsecureTrustManagerFactory.INSTANCE) .build().newEngine(ch.alloc(), host, port); ch.pipeline().addLast(new SslHandler(sslEngine)); } ch.pipeline().addLast(new HttpClientCodec()); ch.pipeline().addLast(new HttpsProxyServerHandler()); } }) .connect(host, port) .addListener((ChannelFuture future) -> { if (future.isSuccess()) { serverChannel = future.channel(); } else { clientChannel.close(); } }); headers.clear(); for (Map.Entry<String, String> entry : request.headers()) { headers.put(entry.getKey(), entry.getValue()); } headers.remove(HttpHeaders.Names.HOST); b.channel(NioSocketChannel.class) .connect(host, port) .addListener((ChannelFuture future) -> { if (future.isSuccess()) { serverChannel = future.channel(); serverChannel.writeAndFlush(request.retain()); clientChannel.read(); } else { clientChannel.close(); } }); } else if (msg instanceof HttpResponse) { HttpResponse response = (HttpResponse) msg; response.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING); response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE); clientChannel.writeAndFlush(response.retain()); } else if (msg instanceof HttpContent) { HttpContent content = (HttpContent) msg; clientChannel.writeAndFlush(content.retain()); if (content instanceof LastHttpContent) { if (isHttps) { sslEngine.closeOutbound(); } clientChannel.flush(); clientChannel.close(); serverChannel.close(); } } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { if (clientChannel.isActive()) { clientChannel.writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_GATEWAY, Unpooled.copiedBuffer("Failure: " + cause.getMessage(), CharsetUtil.UTF_8))) .addListener(ChannelFutureListener.CLOSE); } } } } ``` 这是一个简单的 HTTP/HTTPS 代理服务,可以接收来自客户端的请求,并将其转发到目标服务器。如果请求是 HTTPS 请求,它还会与目标服务器建立安全连接。 在这个示例中,我们使用了 NettyHTTP/HTTPS 编解码器和 SSL 处理程序来处理请求和响应,并将它们转发到目标服务器。在建立与目标服务器的连接时,我们还使用了 Netty 的 Bootstrap 类来创建客户端通道。 当客户端发送请求时,我们从请求中提取目标主机和端口,并使用 Bootstrap 类创建一个新的客户端通道,然后将请求发送到目标服务器。在接收到来自目标服务器的响应时,我们将响应转发给客户端。 如果请求是 HTTPS 请求,我们还需要使用 SSL 处理程序来建立与目标服务器的安全连接。我们使用 Netty 的 SslContextBuilder 类创建一个 SSL 引擎,并将其添加到客户端通道的管道中。在建立与目标服务器的连接时,我们还需要使用 SslHandler 将 SSL 引擎添加到客户端通道的管道中,以便进行 SSL 握手。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值