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

Spring Cloud Gateway过滤器抛自定义RuntimeException未生效及500错误咨询

问题分析与解决方案

首先来说说你为啥会拿到500错误:
当你在GatewayFilter里抛出普通的RuntimeException时,WebFlux的默认异常处理机制会把所有未被明确处理的异常统一映射成500 Internal Server Error。它没办法识别你这个异常对应401状态码,所以直接返回了通用的服务器错误。

接下来给你几种实用的解决办法,你可以根据自己的场景选:

方法1:抛出带状态码的ResponseStatusException

这是最省心的方式,WebFlux原生支持这个异常类,会自动把它转换成对应的HTTP状态码响应。修改你的过滤器代码就行:

@Override
public GatewayFilter apply(Object config) {
    return (exchange, chain) -> {
        ServerHttpRequest httpRequest = exchange.getRequest();
        if (!someUtil.validRequest(httpRequest)) {
            throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Custom error code and message");
        }
        return chain.filter(exchange);
    };
}

这样抛出的异常会被WebFlux正确识别,直接返回401状态码和你自定义的消息。

方法2:自定义全局异常处理器(ErrorWebExceptionHandler)

如果你需要处理更多自定义异常场景,可以实现ErrorWebExceptionHandler来接管网关的异常处理逻辑:

@Component
public class CustomGatewayErrorHandler extends AbstractErrorWebExceptionHandler {

    public CustomGatewayErrorHandler(ErrorAttributes errorAttributes,
                                     ResourceProperties resourceProperties,
                                     ObjectProvider<ViewResolver> viewResolvers,
                                     ServerCodecConfigurer serverCodecConfigurer) {
        super(errorAttributes, resourceProperties, viewResolvers, serverCodecConfigurer);
    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(), this::handleError);
    }

    private Mono<ServerResponse> handleError(ServerRequest request) {
        Throwable throwable = getError(request);
        // 根据异常类型或消息,映射到401状态码
        if (throwable instanceof RuntimeException && throwable.getMessage().contains("401 Unauthorized")) {
            return ServerResponse.status(HttpStatus.UNAUTHORIZED)
                    .contentType(MediaType.APPLICATION_JSON)
                    .bodyValue(Map.of("code", "CUSTOM_401", "message", throwable.getMessage()));
        }
        // 其他异常走默认的500处理
        return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(Map.of("code", "SERVER_ERROR", "message", "Internal server error"));
    }
}

这个处理器会拦截网关里的所有异常,你可以根据异常的类型、内容等自定义返回的状态码和响应体。

方法3:直接构建错误响应(不抛异常)

如果你不想用异常的方式,也可以直接在过滤器里构建401响应,跳过后续的过滤器链:

@Override
public GatewayFilter apply(Object config) {
    return (exchange, chain) -> {
        ServerHttpRequest httpRequest = exchange.getRequest();
        if (!someUtil.validRequest(httpRequest)) {
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
            String body = "{\"code\":\"CUSTOM_401\",\"message\":\"Custom error code and message\"}";
            return response.writeWith(Mono.just(response.bufferFactory().wrap(body.getBytes())));
        }
        return chain.filter(exchange);
    };
}

这种方式更直接,直接终止过滤器链并返回自定义响应,完全绕开了异常的抛出和处理流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:38:55