我正在使用 Spring Webflux (3.2.2) 和 Spring Graphql(3.2.2) 。我已经实现了一个 WebGraphQlInterceptor 来查找请求标头。如果找不到,我将抛出自定义异常。我已经定义了一个控制器建议类,它有一个处理自定义异常的方法,但似乎控制不会转到该建议方法。
@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)));
}
/**
* Handle exceptions.
*
* @param ex the ex
* @param request the request
* @return the response entity
*/
@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)));
}
/**
* Format error.
*
* @param errorDetails the error details
* @return the map
*/
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);
}
}
我错过了什么。
拦截器在数据获取器完成 GraphQL 查询之前就已介入。这意味着控制器级别的异常处理程序机制将不知道此异常,因为它发生在上游。
根据用例,您可以返回自定义 WebGraphQlResponse。这里涉及安全性,因此我将调用 Spring Security 并直接在 HTTP 级别执行此操作。