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

Vert.x OpenAPI v4.5.10 POST请求必填Body验证失败问题求助

Vert.x OpenAPI v4.5.10 POST请求必填Body验证失败问题求助

你好,我仔细看了你的代码和问题描述,发现核心问题出在请求体的读取时机和验证逻辑的配合上,咱们一步步来解决这个问题:

问题根源分析

  1. 你手动创建了RequestValidator,但Vert.x的请求体是异步读取的——如果直接调用requestValidator.validate(ctx.request(), "addUser"),此时请求体可能还没被读取完成,导致验证器误以为请求没有携带Body,抛出The related request does not contain the required body异常。
  2. 虽然你创建RouterBuilder时用了RequestExtractor.withBodyHandler(),但后续手动调用验证器的方式,和RouterBuilder内置的验证逻辑没有配合好,相当于重复验证且时机不对。

解决方案一:使用RouterBuilder内置验证(推荐,更符合框架设计)

Vert.x OpenAPI的RouterBuilder本身已经内置了请求验证逻辑,包括自动读取请求体和验证,不需要手动创建RequestValidator和ResponseValidator,这样代码更简洁也不容易出错。

修改后的代码如下:

public void start() {
    String pathContract = "./api.yaml";
    contract = OpenAPIContract.from(vertx , pathContract);

    contract.onSuccess(contractRes -> {
        // 创建RouterBuilder时指定RequestExtractor,确保请求体被自动读取和验证
        routerBuilder = RouterBuilder.create(vertx, contractRes , RequestExtractor.withBodyHandler());

        // 直接绑定operationId对应的路由,内置验证会自动处理
        routerBuilder.getRoute("addUser").addHandler(this::addUser);
        
        router = routerBuilder.createRouter();

        vertx.createHttpServer().requestHandler(router).listen(8000 , res -> {
            if (res.succeeded()) {
                System.out.println("server is running");
            } else {
                System.out.println("error " + res.cause());
            }
        });
        System.out.println("Validator created successfully.");
    }).onFailure(error -> {
        System.out.println("Failed to load OpenAPI contract: " + error.getMessage());
    });
}

public void addUser(RoutingContext ctx) {
    // 验证已经由RouterBuilder完成,直接获取验证后的请求对象
    ValidatedRequest validatedRequest = RequestExtractor.getValidatedRequest(ctx);
    JsonObject bodyData = validatedRequest.getBody().getJsonObject();
    String name = bodyData.getString("name");

    if (!name.isEmpty()) {
        // 符合OpenAPI定义,返回201状态码
        ctx.response().setStatusCode(201).end("name is : " + name);
    } else {
        ctx.response().setStatusCode(400).end("error: name cannot be empty");
    }
}

解决方案二:手动使用RequestValidator(适合自定义验证场景)

如果你确实需要手动控制验证逻辑,必须确保请求体已经被读取完成后再执行验证,所以要先添加BodyHandler处理请求体:

修改你的addUser方法:

public void addUser(RoutingContext ctx) {
    // 先通过BodyHandler读取请求体,确保验证器能拿到Body内容
    BodyHandler.create().handle(ctx, ar -> {
        if (ar.succeeded()) {
            // 请求体读取完成后再执行验证
            requestValidator.validate(ctx.request(), "addUser").onSuccess(validatedRequest -> {
                JsonObject bodyData = validatedRequest.getBody().getJsonObject();
                String name = bodyData.getString("name");

                if (!name.isEmpty()) {
                    ctx.response().setStatusCode(201).end("name is : " + name);
                } else {
                    ctx.response().setStatusCode(400).end("error " + name);
                }
            }).onFailure(err -> {
                ctx.response().setStatusCode(400).end("error " + err.getMessage());
            });
        } else {
            ctx.response().setStatusCode(400).end("Failed to read request body: " + ar.cause().getMessage());
        }
    });
}

额外注意点

  • 你的OpenAPI YAML里路径是/user,operationId为addUser,和代码里的routerBuilder.getRoute("addUser")匹配正确,这点没问题。
  • 成功响应时记得返回201状态码,和你的OpenAPI定义一致。

备注:内容来源于stack exchange,提问作者Youssef Amerzag

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 09:44:32