当前位置:   article > 正文

【Spring Cloud GateWay】ServerHttpResponseDecorator不生效

serverhttpresponsedecorator

1. BUG描述

在Spring Cloud Gateway使用编码的方式实现一个全局拦截器,在全局拦截器中想要打印响应日志。

于是自己装饰了一个具有打印日志功能的ServerHttpResponseDecorator,但是在转发后的服务返回响应的时候,ServerHttpResponseDecoratorwriteWith却并没有执行。

@Component
@Slf4j
public class CustomGlobaFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //响应日志
        return handleResponse(exchange, chain);
    }

    public Mono<Void> handleResponse(ServerWebExchange exchange, GatewayFilterChain chain) {
        try {
            ServerHttpResponse originalResponse = exchange.getResponse();
            // 缓存数据的工厂
            DataBufferFactory bufferFactory = originalResponse.bufferFactory();
            // 拿到响应码
            HttpStatus statusCode = originalResponse.getStatusCode();
            if (statusCode == HttpStatus.OK) {
                // 装饰,增强能力
                ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
                    // 等调用完转发的接口后才会执行
                    @Override
                    public Mono<Void>  writeWith(Publisher<? extends DataBuffer> body) {
                        log.info("body instanceof Flux: {}", (body instanceof Flux));
                        if (body instanceof Flux) {
                            Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                            // 往返回值里写数据
                            // 拼接字符串
                            return super.writeWith(
                                    fluxBody.map(dataBuffer -> {
                                        byte[] content = new byte[dataBuffer.readableByteCount()];
                                        dataBuffer.read(content);
                                        //释放掉内存
                                        DataBufferUtils.release(dataBuffer);
                                        // 构建日志
                                        StringBuilder sb2 = new StringBuilder(200);
                                        List<Object> rspArgs = new ArrayList<>();
                                        rspArgs.add(originalResponse.getStatusCode());
                                        //data
                                        String data = new String(content, StandardCharsets.UTF_8); 
                                        sb2.append(data);
                                        // 打印日志
                                        log.info("响应结果:" + data);
                                        return bufferFactory.wrap(content);
                                    }));
                        } else {
                            // 8. 调用失败,返回一个规范的错误码
                            log.error("<--- {} 响应code异常", getStatusCode());
                        }
                        return super.writeWith(body);
                    }
                };
                // 设置 response 对象为装饰过的
                return chain.filter(exchange.mutate().response(decoratedResponse).build());
            }
            // 降级处理返回数据
            return chain.filter(exchange); 
        } catch (Exception e) {
            log.error("网关处理响应异常" + e);
            return chain.filter(exchange);
        }
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

2. BUG解决

getOrder方法的返回值设置为-2

@Override
public int getOrder() {
    return -2;
}
  • 1
  • 2
  • 3
  • 4

修改成之后,writeWith方法在服务返回响应的时候就能被调用了。


3. BUG分析

在SpringCloudGateway中,有很多默认的全局过滤器。

img

它们对应的order值如下图所示

img

因为我这里的CustomGlobaFilter实现了Ordered,所以它的order就是它自己设定的值。

否则,它就没有order。

查看了大量信息,最后得知,自定义的GlobaFilter的order必须小于-1,否则标准 NettyWriteResponseFilter 将在过滤器有机会被调用之前发送响应。


参考:

  1. Allow modification of the response body · Issue #47 · spring-cloud/spring-cloud-gateway (github.com)
  2. 获取SpringCloud gateway 响应的response的值,可以查看、修改 - 腾讯云开发者社区-腾讯云 (tencent.com)
  3. gateway的ServerHttpResponseDecorator后不起作用?-有问必答-CSDN问答
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/468232
推荐阅读
相关标签
  

闽ICP备14008679号