前言
通常情况下,我们在部署线上业务服务时,为了统一入口,方便管理以及安全加固等需求,可能都会使用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());
}
}
这样就构建了一个简单的反向代理服务器了,但是这样的问题是不能拦截请求的流,不能有任何额外处理(如果是用作网关则不能使用这样的做法)