vertx router如何作为反向代理服务器转发请求

3,109 阅读1分钟

前言

通常情况下,我们在部署线上业务服务时,为了统一入口,方便管理以及安全加固等需求,可能都会使用nginx等类似工具做一次反向代理,而真正的后端服务是不会暴露在公网中的。而vertx也可以做到该功能,并且由于vertx是基于netty实现的,他的qps远高于nginx,所以这篇文章主要介绍如何实现反向代理

创建反向代理服务器

创建RouterVerticle

public class RouterVerticle extends AbstractVerticle {
    private Logger log;

    @Override
    public void start() {
        this.log = LoggerFactory.getLogger(this.getClass());
        Router router = Router.router(vertx);
        router.get("/ping").handler(PingHandler.create());
        router.route().handler(BodyHandler.create());
        //自定义的代理handler
        router.route().handler(ProxyHandler.create());
        router.route().failureHandler(GlobalErrorHandler.create(getLogPluginHandler()));
        HttpServerOptions options = new HttpServerOptions();
        //增加配置初始长度,规避可能存在的uri过长被服务器拒绝的问题
        options.setMaxInitialLineLength(appConfig.getMaxInitialLineLength());
        vertx.createHttpServer(options).requestHandler(router).listen(appConfig.getPort(), http -> {
            if (http.succeeded()) {
                log.info("HTTP server started on port:" + appConfig.getPort());
            } else {
                log.error("HTTP server start error!", http.cause());
            }
        });

    }

}

ProxyHandler接口

public interface ProxyHandler extends Handler<RoutingContext> {
    static ProxyHandler create(){
        return new ProxyHandlerImpl();
    }
}

ProxyHandlerImpl 实现

public class UploadHandlerImpl implements UploadHandler {

    @Override
    public void handle(RoutingContext context) {
        HttpServerRequest req = context.request();
        //这里是处理请求地址逻辑,具体代码需要看实际业务。这里就不贴实现了
        TargetInfo targetInfo = getTargetInfo(context);
         HttpClient client = vertx.createHttpClient(new HttpClientOptions());
        HttpClientRequest c_req = client.request(VertHttpRequestWrapper.transMethod(request.getMethod()), SocketAddress.inetSocketAddress(targetInfo.getPort(), targetInfo.getHost())
                , targetInfo.getPort(), targetInfo.getHost(), targetInfo.getRemoteUri(), res -> {
                    context.response().setChunked(true);
                    context.response().setStatusCode(res.statusCode());
                    context.response().headers().setAll(res.headers());
                    res.handler(data -> {
                        req.response().write(data);
                    });
                    res.exceptionHandler(ex->{                              
                       //如果异常则返回 context.fail(RouterException.e(RouterCode.REQUEST_ERROR, ex));
                    
                    });
                    res.endHandler((v) -> req.response().end());
                });
        c_req.setChunked(true);
        c_req.headers().setAll(context.request().headers());
        req.handler(c_req::write);
        req.endHandler((v) -> c_req.end());
    }
}

这样就构建了一个简单的反向代理服务器了,但是这样的问题是不能拦截请求的流,不能有任何额外处理(如果是用作网关则不能使用这样的做法)