为何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
相关产品推荐
相关产品推荐

