spring - 使用 Spring Cloud Gateway 进行全局异常处理

标签 spring spring-webflux spring-cloud-gateway

我在 Spring Boot 2.1.5 中使用 Spring Cloud Gateway Greenwich.SR1。我正在尝试为我的下游服务创建网关。网关的部分工作是为下游请求提供全局错误页面。当下游服务返回 HTTP 403 响应时,我希望网关提供合适的错误页面。

我目前正在使用这样的自定义过滤器

public class ForbiddenFilterFactory extends AbstractGatewayFilterFactory<Object> {

    @Override
    public String name() {
        return "Forbidden";
    }

    @Override
    public GatewayFilter apply(Object o) {
        return (exchange, chain) -> chain.filter(exchange).then(
                Mono.defer(() -> {
                    if (!exchange.getResponse().isCommitted() &&
                            HttpStatus.FORBIDDEN.equals(exchange.getResponse().getStatusCode())) {
                        return Mono.error(new ResponseStatusException(HttpStatus.FORBIDDEN));
                    }
                    return Mono.empty();
                }));
    }
}

我也有 403.html文件在 src/main/resources/templates/error/设置。

问题是网关返回一个带有空正文的 403 响应,而不是 html 文件的内容。在调试过程中我可以看到 DefaultErrorWebExceptionHandlerMono<ServerResponse> 的形式创建正确的主体但它从未写过实际的响应。

有没有其他方法可以让它发挥作用?

最佳答案

我通过使用自定义 ServerHttpResponseDecorator 解决了这个问题.代码的关键部分是覆盖 writeWith提供自定义主体的方法:

ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(exchange.getResponse()) {
    @Override
    public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
        if (shouldServeErrorPage(exchange)) {
            exchange.getResponse().getHeaders().setContentLength(-1);
            return errorWebExceptionHandler.handle(exchange, new ResponseStatusException(getHttpStatus(exchange)));
        } else {
            return getDelegate().writeWith(body);
        }
    }

    @Override
    public Mono<Void> writeAndFlushWith(
            Publisher<? extends Publisher<? extends DataBuffer>> body) {
        if (shouldServeErrorPage(exchange)) {
            return writeWith(Flux.from(body).flatMapSequential(p -> p));
        } else {
            return getDelegate().writeAndFlushWith(body);
        }
    }

    private boolean shouldServeErrorPage(ServerWebExchange exchange) {
        HttpStatus statusCode = getHttpStatus(exchange);
        return statusCode.is5xxServerError() || statusCode.is4xxClientError();
    }
};

return chain.filter(exchange.mutate().response(responseDecorator).build());

我在 https://github.com/tine2k/scg-global-error-page 推送了一个工作样本

关于spring - 使用 Spring Cloud Gateway 进行全局异常处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56298502/

相关文章:

java - 如何将 IP 地址绑定(bind)到 Spring 3 @ModelAttribute?

spring-boot - 是否有使用 WebFlux 的 OAuth2 工作示例

load-balancing - 服务器如何发送消息 SSE 在多个服务器实例环境中工作

java - Spring Cloud Gateway 中的身份验证

nginx - Spring Cloud Gateway 和 NGINX

java - Spring Data Mongo : How to return nested object by its field?

spring - 通过 Spring Security 登录后接收 sessionid

java - Maven 依赖项未复制到 Eclipse 中的 WEB-INF/lib

spring-boot - Spring Boot 2 - Webflux - Websocket - 激活压缩

spring-cloud-sleuth - 如何配置 spring-cloud-gateway 以使用侦探记录请求/响应正文