You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 11:37:31