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

为何WebFlux中onErrorResume仅能捕获部分ValidationException?

问题

在WebFlux项目中使用onErrorResume捕获ValidationException时出现差异:

  • Handler的create方法可正常捕获service.createRequest抛出的该异常,返回400;
  • Handler的getRequests方法无法捕获service.getRequests抛出的同类型异常,客户端收到500。

日志显示该ValidationException未被捕获,若将service.getRequests中直接抛出异常改为return Mono.error(...),则可被onErrorResume正常捕获。

相关代码

Handler代码

public Mono<ServerResponse> create(ServerRequest request) {
    return service.createRequest(request).flatMap(c -> ServerResponse.ok()
                    .contentType(APPLICATION_JSON)
                    .bodyValue(new ActionResponseDto<>(true, c, null)))
            .onErrorResume(ValidationException.class, e -> ServerResponse.badRequest()
                    .contentType(APPLICATION_JSON)
                    .bodyValue(new ActionResponseDto<>(false, e.getObject(), e.getErrors())));
}

public Mono<ServerResponse> getRequests(ServerRequest request) {
    return service.getRequests(request)
            .flatMap(res -> ServerResponse.ok()
                    .contentType(APPLICATION_JSON)
                    .bodyValue(PaginationUtil.createPaginatedListResponse(res)))
            .onErrorResume(ValidationException.class, e -> ServerResponse.badRequest().bodyValue("error"));
}

Service代码

public Mono<RequestDto> createRequest(ServerRequest request) {
    // get body
    var requestDto = request.bodyToMono(RequestDto.class);

    // validate and convert to entity
    var entity = requestDto.map(r -> {
        var errors = validator.validate(r);

        if (!errors.isEmpty()) {
            // has errors
            throw new ValidationException(r, errors);
        }

        // has no errors
        // do stuff
    });

    // save on database and return
    // do stuff
});

public Mono<Page<RequestDto>> getRequests(ServerRequest request) {
    try {
        // read query params
        // do stuff
    } catch (Exception e) {
        throw new ValidationException(requestQuery, List.of(new ValidationError("error query params", "message")));
    }

    // get requests from database
    // do stuff
}
原因分析
  • createRequest的异常在Reactive流水线内抛出:createRequest里的异常是在requestDto.map(...)这个Reactive操作符中抛出的,map属于Reactive异步流水线的一部分,抛出的异常会被自动包装为Mono.error(...),后续的onErrorResume能正常捕获并处理。
  • getRequests的异常在Reactive流水线外抛出:getRequests方法在同步执行try-catch时直接抛出异常,这个时机还未进入Reactive的异步执行阶段,异常会作为普通同步异常抛出,绕过了onErrorResume的捕获逻辑,最终被WebFlux全局异常处理器捕获返回500。
解决方案

修改getRequests的异常抛出逻辑,将直接抛出改为返回Mono.error(...),让异常进入Reactive流水线:

public Mono<Page<RequestDto>> getRequests(ServerRequest request) {
    try {
        // read query params
        // do stuff
    } catch (Exception e) {
        return Mono.error(new ValidationException(requestQuery, List.of(new ValidationError("error query params", "message"))));
    }

    // get requests from database
    // do stuff,确保后续逻辑返回Mono<Page<RequestDto>>
}

内容的提问来源于stack exchange,提问作者clema

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 17:07:06