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

如何在@Before切面中捕获异常并向客户端返回正确的HttpResponse

问题根源

你现在的实现存在两个核心错误,直接导致异常无法流入请求响应链路:

  • @Before切面无法适配WebFlux异步场景,你主动调用subscribe()后,权限校验的异步流和原接口的响应流完全独立,校验过程抛出的异常不会被请求链路的异常处理器捕获,甚至主线程不会等待校验逻辑执行完成就提前结束,最终无响应返回抛出NoHttpResponseException
  • @Before切面没有能力暂停原方法执行等待异步校验结果,校验还没出结果原接口就已经开始执行,权限校验完全失效
改造方案

1. 替换为@Around切面,串连校验流与原接口流

仅针对返回值为Mono的WebFlux接口做切点,把权限校验逻辑和原方法执行逻辑串到同一条响应流中:

@Around("@annotation(demo.webflux.test.PermittedByRole) && execution(public reactor.core.publisher.Mono *(..))")
public Object checkPermission(ProceedingJoinPoint joinPoint) throws Throwable {
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    PermittedByRole annotation = signature.getMethod().getAnnotation(PermittedByRole.class);
    String operation = annotation.operation();
    
    return testService.testAction(operation)
            .filter(Boolean::booleanValue)
            // 校验不通过抛自定义异常,方便统一处理
            .switchIfEmpty(Mono.defer(() -> Mono.error(new PermissionDeniedException("权限不足"))))
            // 校验通过才执行原接口逻辑
            .flatMap(allow -> (Mono<?>) joinPoint.proceed());
}

2. 新增自定义异常与全局异常处理器

统一处理权限校验异常,返回标准HTTP 403响应:

// 自定义权限异常
public class PermissionDeniedException extends RuntimeException {
    public PermissionDeniedException(String message) {
        super(message);
    }
}

// WebFlux全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(PermissionDeniedException.class)
    public Mono<ResponseEntity<Map<String, Object>>> handlePermissionDenied(PermissionDeniedException e) {
        Map<String, Object> resp = new HashMap<>();
        resp.put("code", 403);
        resp.put("message", e.getMessage());
        return Mono.just(ResponseEntity.status(HttpStatus.FORBIDDEN).body(resp));
    }
}

3. 修正接口阻塞逻辑

WebFlux接口中禁止使用Thread.sleep阻塞事件循环线程,替换为非阻塞延迟方法:

@PermittedByRole(operation = "test")
@GetMapping(value = "/oac")
public Mono<TestObject> base() {
    return Mono.delay(Duration.ofSeconds(3))
            .thenReturn(new TestObject().setFieldOne("one").setFieldTwo("two"));
}

改造后权限校验的异常会在请求响应链路中正常传播,全局异常处理器可以直接捕获返回标准响应,无需额外自定义WebFilter处理。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 01:45:05