Vert.x中如何按路径前缀将请求转发至对应Verticle处理?
Vert.x 统一转发前缀路由到子Verticle的实现方案
核心逻辑
主Verticle仅负责拦截所有/example/*前缀的请求,将请求的核心信息(路径、方法、参数、Body)通过EventBus发送给ExampleVerticle;ExampleVerticle内部维护独立的Router处理所有子路由,处理完成后将响应结果回传,由主Verticle返回给客户端。
分步实现
1. 定义请求/响应传输对象
创建序列化的POJO,用于在EventBus中传递请求和响应数据:
import io.vertx.core.http.HttpMethod; import io.vertx.core.MultiMap; import java.io.Serializable; public class RouteRequest implements Serializable { private String subPath; // 去掉/example前缀后的子路径,比如/hello private HttpMethod method; private MultiMap params; private String body; // 全参构造器 public RouteRequest(String subPath, HttpMethod method, MultiMap params, String body) { this.subPath = subPath; this.method = method; this.params = params; this.body = body; } // Getter和Setter方法省略 } public class RouteResponse implements Serializable { private int statusCode; private MultiMap headers; private String body; public RouteResponse(int statusCode, MultiMap headers, String body) { this.statusCode = statusCode; this.headers = headers; this.body = body; } // Getter和Setter方法省略 }
2. 主Verticle配置路由转发
在主Verticle中匹配前缀路由,提取请求信息并发送到EventBus:
import io.vertx.core.AbstractVerticle; import io.vertx.core.http.HttpMethod; import io.vertx.core.MultiMap; import io.vertx.ext.web.Router; public class MainVerticle extends AbstractVerticle { private static final String EXAMPLE_BUS_ADDR = "example.route.handler"; @Override public void start() { Router mainRouter = Router.router(vertx); // 拦截所有/example/*的请求 mainRouter.route("/example/*").handler(ctx -> { // 提取子路径(去掉/example前缀) String subPath = ctx.request().path().replaceFirst("^/example", ""); HttpMethod method = ctx.request().method(); MultiMap params = ctx.request().params(); // 读取请求Body ctx.request().bodyHandler(bodyBuf -> { String body = bodyBuf.toString(); RouteRequest request = new RouteRequest(subPath, method, params, body); // 发送请求到EventBus并等待响应 vertx.eventBus().request(EXAMPLE_BUS_ADDR, request, reply -> { if (reply.succeeded()) { RouteResponse response = (RouteResponse) reply.result().body(); // 将子Verticle的响应返回给客户端 ctx.response() .setStatusCode(response.getStatusCode()) .putHeaders(response.getHeaders()) .end(response.getBody()); } else { ctx.response().setStatusCode(500).end("Internal Server Error"); } }); }); }); // 启动HTTP服务器 vertx.createHttpServer().requestHandler(mainRouter).listen(8080); } }
3. ExampleVerticle处理子路由
在ExampleVerticle中初始化内部Router,监听EventBus地址并处理请求:
import io.vertx.core.AbstractVerticle; import io.vertx.core.MultiMap; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; public class ExampleVerticle extends AbstractVerticle { private static final String EXAMPLE_BUS_ADDR = "example.route.handler"; private Router subRouter; @Override public void start() { // 初始化子路由 subRouter = Router.router(vertx); // 处理子路径/hello subRouter.get("/hello").handler(ctx -> { RouteResponse response = new RouteResponse(200, MultiMap.caseInsensitiveMultiMap(), "Hello from ExampleVerticle!"); replyToMainVerticle(ctx, response); }); // 处理子路径/:name subRouter.get("/:name").handler(ctx -> { String name = ctx.pathParam("name"); RouteResponse response = new RouteResponse(200, MultiMap.caseInsensitiveMultiMap(), "Hello, " + name + "!"); replyToMainVerticle(ctx, response); }); // 监听EventBus地址,处理主Verticle发来的请求 vertx.eventBus().consumer(EXAMPLE_BUS_ADDR, message -> { RouteRequest request = (RouteRequest) message.body(); // 创建模拟上下文交给子Router处理 RoutingContext mockCtx = createMockCtx(request, message); subRouter.handle(mockCtx); }); } // 回传响应到主Verticle private void replyToMainVerticle(RoutingContext ctx, RouteResponse response) { io.vertx.core.eventbus.Message<Object> message = ctx.get("message"); message.reply(response); } // 创建模拟RoutingContext适配子Router private RoutingContext createMockCtx(RouteRequest request, io.vertx.core.eventbus.Message<Object> message) { return new RoutingContext() { @Override public String path() { return request.getSubPath(); } @Override public String pathParam(String name) { return subRouter.routeMatcher().extractPathParam(request.getSubPath(), ":" + name); } @Override public MultiMap queryParams() { return request.getParams(); } @Override public void put(String key, Object value) { if ("message".equals(key)) { super.put(key, value); } } // 其他未用到的方法可返回默认值或抛出UnsupportedOperationException @Override public Router router() { return subRouter; } }.put("message", message); } }
更简洁的替代方案:使用Vert.x ProxyHandler
如果不想手动模拟上下文,可以用官方提供的工具类简化转发,无需手动处理序列化:
// 主Verticle中配置ProxyHandler import io.vertx.ext.web.handler.ProxyHandler; mainRouter.route("/example/*").handler(ProxyHandler.create(vertx, EXAMPLE_BUS_ADDR)); // ExampleVerticle中注册RouterConsumer import io.vertx.ext.web.handler.RouterConsumer; RouterConsumer.create(subRouter).register(vertx, EXAMPLE_BUS_ADDR);
这种方式下Vert.x会自动处理请求转发和响应回传,代码量大幅减少,适合快速开发。
内容的提问来源于stack exchange,提问作者Vansh Sharma
相关产品推荐
相关产品推荐

