Spring Webflux+GraphQL拦截器异常未进入ControllerAdvice处理
问题描述
使用Spring Webflux(3.2.2)和Spring GraphQL(3.2.2)框架,实现了WebGraphQlInterceptor用于检查请求头,当未找到指定请求头时抛出CustomException。但自定义的@ControllerAdvice类中,处理CustomException的@GraphQlExceptionHandler方法并未被触发,异常没有按预期处理。
相关代码
GraphQL异常处理器
@ControllerAdvice @Slf4j @Order(Ordered.HIGHEST_PRECEDENCE) public class GraphQLExceptionHandler { @GraphQlExceptionHandler(CustomException.class) public GraphQLError handleCustomException(CustomException e) { return GraphQLError.newError() .errorType(resolve(e.errorCode)) .message(e.getMessage()) .build(); } @GraphQlExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public GraphQLError handleException(Exception e) { return GraphQLError.newError() .errorType(ErrorType.INTERNAL_ERROR) .message(e.getMessage()) .build(); } @ExceptionHandler(CustomException.class) public final Mono<ResponseEntity<Map<String, Object>>> handleCustomExceptions(CustomException ex, ServerWebExchange exchange) { log.info("Application Exception occurred : {} ", ex.getMessage()); ErrorDetails errorDetails = new ErrorDetails(ex.errorCode, ex.getMessage(), ex, exchange.getRequest().getPath().value()); return Mono.just(ResponseEntity.status(HttpStatus.resolve(ex.errorCode)).body(formatError(errorDetails))); } @ResponseStatus(INTERNAL_SERVER_ERROR) @ExceptionHandler(Exception.class) public final Mono<ResponseEntity<Map<String, Object>>> handleExceptions(Exception ex, ServerWebExchange exchange) { log.error("Exception occurred : {0}", ex); ErrorDetails errorDetails = new ErrorDetails(INTERNAL_SERVER_ERROR.value(), "Something went wrong, please try again after sometime", ex, exchange.getRequest().getPath().value()); return Mono.just(ResponseEntity.status(INTERNAL_SERVER_ERROR).body(formatError(errorDetails))); } private Map<String, Object> formatError(ErrorDetails errorDetails) { Map<String, Object> error = new HashMap<>(); error.put("errors", errorDetails); return error; } private ErrorType resolve(int errorCode) { return switch (errorCode) { case 401 -> ErrorType.UNAUTHORIZED; case 403 -> ErrorType.FORBIDDEN; case 404 -> ErrorType.NOT_FOUND; default -> ErrorType.INTERNAL_ERROR; }; } }
请求头拦截器
@Component public class RequestHeaderInterceptor implements WebGraphQlInterceptor { public static final String AUTHORIZATION_HEADER_KEY = "Authorization"; @NotNull @Override public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) { String value = request.getHeaders().getFirst(AUTHORIZATION_HEADER_KEY); if (value == null) { throw new CustomException(ErrorMessage.AUTH_ID_NOT_FOUND); } request.configureExecutionInput((executionInput, builder) -> builder.graphQLContext(Collections.singletonMap("authHeader", value)).build()); return chain.next(request); } }
问题原因与解决方法
核心问题:拦截器中异常抛出方式错误
WebGraphQlInterceptor运行在WebFlux异步非阻塞的请求链路中,直接同步抛出CustomException会被WebFlux的全局异常处理器(即你代码中的@ExceptionHandler方法)捕获,而非Spring GraphQL的@GraphQlExceptionHandler。只有通过Mono.error()抛出异常,才能让异常进入GraphQL的处理链路,被对应的异常处理器处理。
修改后的拦截器代码
@Component public class RequestHeaderInterceptor implements WebGraphQlInterceptor { public static final String AUTHORIZATION_HEADER_KEY = "Authorization"; @NotNull @Override public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) { String value = request.getHeaders().getFirst(AUTHORIZATION_HEADER_KEY); if (value == null) { // 改为返回Mono.error,将异常注入异步链路 return Mono.error(new CustomException(ErrorMessage.AUTH_ID_NOT_FOUND)); } request.configureExecutionInput((executionInput, builder) -> builder.graphQLContext(Collections.singletonMap("authHeader", value)).build()); return chain.next(request); } }
额外注意事项
- 确保CustomException是运行时异常:自定义异常需继承
RuntimeException,避免在异步链路中需要额外处理检查型异常。 - GraphQL异常处理器的@ResponseStatus无效:GraphQL规范推荐响应HTTP状态码为200,错误信息放在响应体的
errors数组中。如果需要修改HTTP状态码,建议通过WebFilter或在拦截器中操作ServerWebExchange实现,而非依赖@ResponseStatus。 - @Order注解的作用:当前
GraphQLExceptionHandler已设置@Order(Ordered.HIGHEST_PRECEDENCE),确保它优先于其他异常处理器执行,无需调整。
内容的提问来源于stack exchange,提问作者Ladu anand
相关产品推荐
相关产品推荐

