您的位置 首页 java

Java,Netty,实现HTTP代理服务器,IP安全过滤,代码案例分享

介绍说明

普通代理(Http)

Http,RFC 7230中描述为普通代理,其代理扮演的是“中间人”角色,对于连接到它的客户端来说,它是服务端,对于要连接的服务端来说,它是客户端,代理服务器负责在两端之间来回传送HTTP报文。

隧道代理(Https)

Https,代理服务器是一个web服务器,影响了客户端和服务器的 TLS 加密连接的。此时主要使用 RFC 中定义的通过 Web 代理服务器用隧道方式传输基于 tcp 的协议的隧道代理方式,它的主要流程为:

1、浏览器首先发送Http Connect请求给代理服务器,发送目标主机信息。

2、代理服务器建立和目标主机的tcp链接,并向浏览器回应Connection Established应答。

3、浏览器将请求发送给代理服务器,代理服务器透传给目标主机。

4、目标主机将响应回给代理服务器,代理服务器将响应回给浏览器。

Netty 实现

Netty高性能网络框架,支持OIO(阻塞式传输)/NIO(非阻塞式传输)等能力,同时屏蔽了网络底层现,使开发人员专注于应用逻辑开发。

Netty框架中大量运用了直接内存用来提高效率,编写代码时要注意及时释放资源,避免 内存泄漏 问题。

代码分享

 <dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15to18</artifactId>
    <version>1.70</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk15to18</artifactId>
    <version>1.70</version>
</dependency>
<!-- netty-all -->
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.60.Final</version>
</dependency>  
 package com.what21.netty03.demo01;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel. socket .nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

import  java .net.InetSocketAddress;

public class HttpServer {

     private  String serverName;
    private String bindHost;
    private int bindPort;

    public HttpServer(String serverName, String bindHost, int bindPort) {
        this.serverName = serverName;
        this. bind Host = bindHost;
        this.bindPort = bindPort;
    }

    public  void  start() throws  Exception  {
        // 用于Acceptor的主" 线程池 "
        EventLoopGroup bossEventGroup = new NioEventLoopGroup();
        // 初始化==>用于I/O工作的从"线程池"
        EventLoopGroup workerEventGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            // group方法设置主从线程池
            serverBootstrap.group(bossEventGroup, workerEventGroup);
            // 指定通道channel类型,服务端为:NioServerSocketChannel
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024);
            serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);
            serverBootstrap.handler(new LoggingHandler(LogLevel.INFO));
            serverBootstrap.childHandler(new HttpServerInitializer());
            ChannelFuture bindFuture = null;
            if ("0.0.0.0".equalsIgnoreCase(this.bindHost)) {
                bindFuture = serverBootstrap.bind(this.bindPort).sync();
            } else {
                InetSocketAddress bindAddress = new InetSocketAddress(this.bindHost, this.bindPort);
                bindFuture = serverBootstrap.bind(bindAddress).sync();
            }
            Channel parentChannel = bindFuture.channel();
            bindFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture channelFuture) throws Exception {
                    if (channelFuture.isSuccess()) {
                        System.out.println(HttpServer.this.serverName + ",绑定监听成功," + channelFuture.channel().localAddress());
                    } else {
                        System.err.println(HttpServer.this.serverName + ",绑定监听失败!" + channelFuture.cause());
                    }
                }
            });
            ChannelFuture closeFuture = bindFuture.channel().closeFuture().sync();
            closeFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture channelFuture) throws Exception {
                    if (channelFuture.isSuccess()) {
                        System.out.println(HttpServer.this.serverName + ",停止监听成功," + channelFuture.channel().localAddress());
                    } else {
                        System.err.println(HttpServer.this.serverName + ",停止监听失败!" + channelFuture.cause());
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 优雅退出,释放"线程池"
            if (bossEventGroup != null) {
                bossEventGroup. shutdown Gracefully();
            }
            if (workerEventGroup != null) {
                workerEventGroup.shutdownGracefully();
            }
        }
    }

    public  static  void main(String[] args) {
        try {
            new HttpServer("HTTP代理服务器", "0.0.0.0", 8888).start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}  
 package com.what21.netty03.demo01;

import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.ipfilter.IpFilterRule;
import io.netty.handler.ipfilter.IpFilterRuleType;
import io.netty.handler.ipfilter.IpSubnetFilterRule;
import io.netty.handler.ipfilter.RuleBasedIpFilter;

import java.net.InetSocketAddress;

public class HttpServerInitializer  extends  ChannelInitializer<Channel> {

    @Override
    protected void initChannel(Channel ch) throws Exception {
        IpSubnetFilterRule rule1 = new  Ip SubnetFilterRule("192.168.119.1", 24, IpFilterRuleType.ACCEPT);
        IpSubnetFilterRule rule2 = new IpSubnetFilterRule(" 127.0.0.1 ", 32, IpFilterRuleType.REJECT);
        IpFilterRule rejectAll = new IpFilterRule() {
            @Override
            public boolean matches(InetSocketAddress remoteAddress) {
                return true;
            }

            @Override
            public IpFilterRuleType ruleType() {
                return IpFilterRuleType.REJECT;
            }
        };
        RuleBasedIpFilter filter = new RuleBasedIpFilter(rule1, rejectAll);
        ch.pipeline().addLast("ipFilter", filter);
        ch.pipeline().addLast("httpServerCodec", new HttpServerCodec());
        ch.pipeline().addLast("httpObjectAggregator", new HttpObjectAggregator(65536));
        ch.pipeline().addLast("httpProxyServerHandler", new HttpProxyServerHandler());
    }

}  
 package com.what21.netty03.demo01;

import io.netty. Bootstrap .Bootstrap;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;

public class HttpProxyServerHandler extends ChannelInboundHandlerAdapter {

    private ChannelFuture cf;
    private String host;
    private int port;

    @Override
    public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
        if (msg  instanceof  FullHttp request ) {
            FullHttpRequest request = (FullHttpRequest) msg;
            String host = request.headers().get("Host");
            String[] temp = host.split(":");
            int port = 80;
            if (temp.length > 1) {
                port = Integer.parseInt(temp[1]);
            } else {
                if (request.uri().indexOf("https") == 0) {
                    port = 443;
                }
            }
            this.host = temp[0];
            this.port = port;
            String authorization = request.headers().get("Authorization");
            System.out.println("http basic认证信息:" + authorization);
            if ("CONNECT".equalsIgnoreCase(request.method().name())) { // HTTPS建立代理握手
                HttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
                ctx.writeAndFlush(response);
                ctx.pipeline().remove("httpServerCodec");
                ctx.pipeline().remove("httpObjectAggregator");
                return;
            }
            //连接至目标服务器
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(ctx.channel().eventLoop()) // 注册 线程 池
                    .channel(ctx.channel().getClass()) // 使用NioSocketChannel来作为连接用的channel类
                    .handler(new HttpProxyInitializer(ctx.channel()));

            ChannelFuture cf = bootstrap.connect(temp[0], port);
            cf.addListener(new ChannelFutureListener() {
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (future.isSuccess()) {
                        future.channel().writeAndFlush(msg);
                    } else {
                        ctx.channel().close();
                    }
                }
            });
//            ChannelFuture cf = bootstrap.connect(temp[0], port).sync();
//            cf.channel().writeAndFlush(request);
        } else { // https 只转发数据,不做处理
            if (cf == null) {
                //连接至目标服务器
                Bootstrap bootstrap = new Bootstrap();
                bootstrap.group(ctx.channel().eventLoop()) // 复用客户端连接线程池
                        .channel(ctx.channel().getClass()) // 使用NioSocketChannel来作为连接用的channel类
                        .handler(new ChannelInitializer() {

                            @Override
                            protected void initChannel(Channel ch) throws Exception {
                                ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                                    @Override
                                    public void channelRead(ChannelHandlerContext ctx0, Object msg) throws Exception {
                                        ctx.channel().writeAndFlush(msg);
                                    }
                                });
                            }
                        });
                cf = bootstrap.connect(host, port);
                cf.addListener(new ChannelFutureListener() {
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (future.isSuccess()) {
                            future.channel().writeAndFlush(msg);
                        } else {
                            ctx.channel().close();
                        }
                    }
                });
            } else {
                cf.channel().writeAndFlush(msg);
            }
        }
    }

}  
 package com.what21.netty03.demo01;

import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;

public class HttpProxyInitializer extends ChannelInitializer {

    private Channel clientChannel;

    public HttpProxyInitializer(Channel clientChannel) {
        this.clientChannel = clientChannel;
    }

    @Override
    protected void initChannel(Channel ch) throws Exception {
        ch.pipeline().addLast(new HttpClientCodec());
        ch.pipeline().addLast(new HttpObjectAggregator(512 * 1024));
        ch.pipeline().addLast(new HttpProxyClientHandler(clientChannel));
    }

}  
 package com.what21.netty03.demo01;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.FullHttpResponse;

public class HttpProxyClientHandler extends ChannelInboundHandlerAdapter {

    private Channel clientChannel;

    public HttpProxyClientHandler(Channel clientChannel) {
        this.clientChannel = clientChannel;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        FullHttpResponse response = (FullHttpResponse) msg;
        //修改http响应体返回至客户端
        response.headers().add("response", "from proxy");
        clientChannel.writeAndFlush(msg);
    }

}  

文章来源:智云一二三科技

文章标题:Java,Netty,实现HTTP代理服务器,IP安全过滤,代码案例分享

文章地址:https://www.zhihuclub.com/187916.shtml

关于作者: 智云科技

热门文章

网站地图