Spring Cloud Gateway因基于WebFlux而不支持@ControllerAdvice和@ExceptionHandler,需自定义继承DefaultErrorWebExceptionHandler的JsonExceptionHandler并以@Bean+@Order(-1)注册,重写getErrorAttributes()和getRoutingFunction()方法,配合AcceptHeaderViewResolver确保返回JSON格式统一异常响应。

Spring Cloud Gateway 基于 WebFlux(响应式编程),不走 Spring MVC 的拦截链路,所以 @ControllerAdvice 和 @ExceptionHandler 在网关层默认无效。要实现全局异常拦截并返回统一 JSON 格式响应,必须替换默认的 ErrorWebExceptionHandler,自定义一个继承 DefaultErrorWebExceptionHandler 的处理器。
核心思路:替换 WebFlux 默认异常处理器
Gateway 启动时会自动装配 ErrorWebFluxAutoConfiguration,其中注册了 DefaultErrorWebExceptionHandler Bean。我们通过 @Bean + @Order(-1) 提前注入自定义实现,覆盖默认行为。
- 自定义类需继承
DefaultErrorWebExceptionHandler - 重写
getErrorAttributes()方法,提取异常类型、状态码、业务消息 - 重写
renderErrorResponse()或依赖父类逻辑,确保返回体为 JSON(而非 HTML 或默认 error 页面) - 在构造器中注入
ErrorAttributes、ResourceProperties等必要组件
关键代码:自定义 JsonExceptionHandler
以下是一个轻量但完整的实现示例:
public class JsonExceptionHandler extends DefaultErrorWebExceptionHandler {
public JsonExceptionHandler(ErrorAttributes errorAttributes,
ResourceProperties resourceProperties,
ErrorProperties errorProperties,
ApplicationContext applicationContext) {
super(errorAttributes, resourceProperties, errorProperties, applicationContext);
}
@Override
protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
Throwable error = super.getError(request);
int status = HttpStatus.INTERNAL_SERVER_ERROR.value();
String message = "系统异常";
if (error instanceof NotFoundException) {
status = HttpStatus.NOT_FOUND.value();
message = "请求路径不存在";
} else if (error instanceof CustomException) {
CustomException ce = (CustomException) error;
status = ce.getStatus();
message = ce.getMessage();
} else if (error instanceof ResponseStatusException) {
status = ((ResponseStatusException) error).getStatus().value();
message = error.getLocalizedMessage();
}
Map<String, Object> result = new HashMap<>();
result.put("code", status);
result.put("message", message);
result.put("timestamp", Instant.now().toString());
return result;
}
@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}
}
注意:getRoutingFunction 必须重写,否则可能 fallback 到默认 HTML 渲染逻辑。
立即学习“Java免费学习笔记(深入)”;
配置生效:注册为 Bean
在配置类中声明该处理器,并确保优先级最高:
@Configuration
public class ExceptionConfig {
@Bean
@Order(-1)
public ErrorWebExceptionHandler errorWebExceptionHandler(
ErrorAttributes errorAttributes,
ResourceProperties resourceProperties,
ErrorProperties errorProperties,
ApplicationContext applicationContext,
ServerCodecConfigurer serverCodecConfigurer) {
JsonExceptionHandler exceptionHandler = new JsonExceptionHandler(
errorAttributes, resourceProperties, errorProperties, applicationContext);
exceptionHandler.setViewResolvers(getViewResolvers(applicationContext));
exceptionHandler.setMessageWriters(serverCodecConfigurer.getWriters());
exceptionHandler.setMessageReaders(serverCodecConfigurer.getReaders());
return exceptionHandler;
}
private List<ViewResolver> getViewResolvers(ApplicationContext context) {
ViewResolver viewResolver = new AcceptHeaderViewResolver(MediaType.APPLICATION_JSON);
return Collections.singletonList(viewResolver);
}
}
其中 AcceptHeaderViewResolver 保证响应 Content-Type 为 application/json。
配合业务异常统一抛出
网关内或下游转发失败时,建议主动抛出自定义异常(如 CustomException),便于在 getErrorAttributes 中精准识别和映射:
- 继承
RuntimeException,避免强制 try-catch - 携带
code(业务码)和status(HTTP 状态码)两个字段 - 在 Filter 或 GlobalFilter 中捕获转发异常(如
ConnectException、TimeoutException)后包装成CustomException再抛出
例如在自定义 GlobalFilter 中:
if (exchange.getResponse().getStatusCode() == null) {
throw new CustomException(503, "服务不可用,请稍后再试");
}
不复杂但容易忽略:WebFlux 的异常处理是响应式链路,必须从 ErrorWebExceptionHandler 入口切入,绕过 MVC 体系才能真正统一管控所有网关层异常。


















