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

Spring Web Flux函数式端点自定义异常抛出与全局处理问题求助

Spring Web Flux函数式端点自定义异常抛出与全局处理问题求助

兄弟,我看了你遇到的问题了,咱们一步步来拆解和解决:

为什么你的代码里USER NOT FOUND!!!永远打不出来?

核心原因是你对Reactor中**Flux的行为理解有点偏差:当repo.findByFirstName(req.pathVariable("name"))查询不到匹配的学生时,这个Flux是空的——它不会发射任何元素,直接进入onComplete状态。而handle操作符的回调函数只有在Flux发射元素的时候才会执行**,所以你写的stu==null的分支根本不会被触发,自然也就不会抛出自定义异常。

怎么修改才能正确抛出自定义异常?

根据你的业务场景(按名字查学生,可能是单个或多个结果),给你两种可行的方案:

方案1:适合「按名字查最多一个学生」的场景

如果你的业务逻辑里,学生名字是唯一的,那直接把Flux转成Mono,用switchIfEmpty来处理空结果的情况,代码更简洁:

public Mono<ServerResponse> getStudentByName(ServerRequest req) {
    String name = req.pathVariable("name");
    return repo.findByFirstName(name)
            // 期望最多一个结果,找不到会触发switchIfEmpty
            .single()
            .switchIfEmpty(Mono.error(new UserNotFoundException("USER NOT FOUND")))
            .flatMap(student -> ServerResponse.ok().bodyValue(student));
}

方案2:适合「允许多个学生重名,但要处理无匹配结果」的场景

如果确实需要保留Flux,那可以用defaultIfEmpty(null)让空Flux发射一个null元素,这样handle的回调就能捕获到并抛出异常:

public Mono<ServerResponse> getStudentByName(ServerRequest req) {
    String name = req.pathVariable("name");
    Flux<Student> studentFlux = repo.findByFirstName(name)
            // 当Flux为空时,发射一个null元素
            .defaultIfEmpty(null)
            .handle((stu, sink) -> {
                if (stu == null) {
                    System.out.println("USER NOT FOUND!!!");
                    sink.error(new UserNotFoundException("USER NOT FOUND"));
                } else {
                    System.out.println("OK OK OK OK");
                    sink.next(stu);
                }
            });

    return ServerResponse.ok().body(studentFlux, Student.class);
}

关于全局异常处理的注意点

你提到用@RestControllerAdvice做全局异常处理,但要注意:@RestControllerAdvice主要是处理注解式控制器(比如@RestController)的异常,对于函数式端点(你现在用的ServerRequest/ServerResponse这种),需要自定义ErrorWebExceptionHandler来实现全局异常处理,示例代码如下:

@Component
public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {

    public GlobalErrorWebExceptionHandler(ErrorAttributes errorAttributes, 
                                         WebProperties webProperties, 
                                         ApplicationContext applicationContext) {
        super(errorAttributes, webProperties.getResources(), applicationContext);
    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        // 匹配所有请求,统一处理异常
        return RouterFunctions.route(RequestPredicates.all(), this::handleException);
    }

    private Mono<ServerResponse> handleException(ServerRequest request) {
        Throwable error = getError(request);
        
        // 处理自定义的UserNotFoundException
        if (error instanceof UserNotFoundException) {
            return ServerResponse.status(HttpStatus.NOT_FOUND)
                    .bodyValue(Map.of(
                            "status", HttpStatus.NOT_FOUND.value(),
                            "message", error.getMessage()
                    ));
        }

        // 处理其他通用异常
        return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .bodyValue(Map.of(
                        "status", HttpStatus.INTERNAL_SERVER_ERROR.value(),
                        "message", "Internal Server Error"
                ));
    }
}

这样当你的自定义异常抛出后,全局异常处理器就能捕获并返回你想要的自定义响应了。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 07:28:07