Spring云网关的全局异常处理

Spring云网关的全局异常处理,spring,spring-webflux,spring-cloud-gateway,Spring,Spring Webflux,Spring Cloud Gateway,我正在使用SpringCloudGatewayGreenwich.SR1和SpringBoot2.1.5。我正在尝试为我的下游服务创建一个网关。网关的部分工作是为下游请求提供全局错误页。当下游服务返回HTTP 403响应时,我希望网关提供一个拟合错误页面 我目前正在使用这样的自定义过滤器 公共类禁止FilterFactory扩展AbstractGatewayFilterFactory{ @凌驾 公共字符串名称(){ 返回“禁止”; } @凌驾 应用公共网关筛选器(对象o){ return(exc

我正在使用SpringCloudGatewayGreenwich.SR1和SpringBoot2.1.5。我正在尝试为我的下游服务创建一个网关。网关的部分工作是为下游请求提供全局错误页。当下游服务返回HTTP 403响应时,我希望网关提供一个拟合错误页面

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

公共类禁止FilterFactory扩展AbstractGatewayFilterFactory{
@凌驾
公共字符串名称(){
返回“禁止”;
}
@凌驾
应用公共网关筛选器(对象o){
return(exchange,chain)->chain.filter(exchange)。然后(
单声道延迟(()->{
如果(!exchange.getResponse().isCommitted())&&
HttpStatus.FORBIDDEN.equals(exchange.getResponse().getStatusCode()){
返回Mono.error(新的ResponseStatusException(HttpStatus.FORBIDDEN));
}
返回Mono.empty();
}));
}
}
我还在
src/main/resources/templates/error/
中设置了一个
403.html
文件

问题是网关返回403响应,返回的是一个空正文,而不是html文件的内容。在调试期间,我可以看到
DefaultErrorWebExceptionHandler
Mono
的形式创建了正确的主体,但它从未写入实际响应


有没有其他方法可以让它工作?

我通过使用定制的
服务器HttpResponseDecorator
解决了这个问题。代码的关键部分是使用方法覆盖
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());
ServerHttpResponseDecorator responseDecorator=new ServerHttpResponseDecorator(exchange.getResponse()){
@凌驾

public Mono writeWith(Publishermaybe)可能是因为其他内容已写入响应?客户端上的响应为空。此筛选器中返回Mono.error。您是在收到响应后执行此操作的,因此我的问题是。