monkeyWie / proxyee

HTTP proxy server,support HTTPS&websocket.MITM impl,intercept and tamper HTTPS traffic.
MIT License
1.52k stars 567 forks source link

请教下,我想根据请求参数的不同代理到不同的目标服务器上,切换过程中会失去响应 #117

Open zhaocheng-dev opened 3 years ago

zhaocheng-dev commented 3 years ago

我想做个代理,目的是根据用户请求参数的不同代理到不同的目标服务器上, 比如/get_by_id?id=123&target=doamin1.com就代理到domain.com/get_by_id?id=123。 但是我发现当我切换的过程中会失去响应,不明白为啥。

    private synchronized void handleProxyData(Channel channel, Object msg, boolean isHttp) {
        String domain = interceptPipeline.getRequestProto().getHost();
        ChannelFuture cf = domain2Cf.get(interceptPipeline.getRequestProto().getHost());
        log.error(" debug info :\n this:\n{}\n ,channel:\n{}\n cf:\n{}\n,msg:\n{}\n\n",
                this, channel, cf, msg);
        if (cf == null) {
            // connection异常 还有HttpContent进来,不转发
            if (isHttp && !(msg instanceof HttpRequest)) {
                return;
            }
            ChannelInitializer<Channel> channelInitializer = isHttp ? new HttpProxyInitializer(channel)
                    : new TunnelProxyInitializer(channel);
            Bootstrap bootstrap = new Bootstrap();
            // 注册线程池 使用NioSocketChannel来作为连接用的channel类
            bootstrap.group(serverConfig.getProxyLoopGroup())
                    .channel(NioSocketChannel.class)
                    .handler(channelInitializer);
            List<Object> requestList = Lists.newArrayList();
            domain2RequestList.put(domain, requestList);

            RequestProto requestProto = interceptPipeline.getRequestProto();
            cf = bootstrap.connect(requestProto.getHost(), requestProto.getPort());
            cf.addListener((ChannelFutureListener) future -> {
                if (future.isSuccess()) {
                    future.channel().writeAndFlush(msg);
                    synchronized (requestList) {
                        requestList.forEach(obj -> future.channel().writeAndFlush(obj));
                        requestList.clear();
                        isConnect = true;
                    }
                } else {
                    requestList.forEach(ReferenceCountUtil::release);
                    requestList.clear();
                    getExceptionHandle().beforeCatch(channel, future.cause());
                    future.channel().close();
                    channel.close();
                }
            });
            domain2Cf.put(domain, cf);
        } else {
            List<Object> requestList = domain2RequestList.get(domain);
            synchronized (requestList) {
                if (isConnect) {
                    cf.channel().writeAndFlush(msg);
                } else {
                    requestList.add(msg);
                }
            }
        }
    }
monkeyWie commented 3 years ago

可以自定义拦截器来实现这个需求,参考:https://github.com/monkeyWie/proxyee/blob/master/src/test/java/com/github/monkeywie/proxyee/InterceptForwardHttpProxyServer.java