• 获取SpringCloud gateway响应的response的值,记录踩坑


    最近在做网关改造,想要通过Gateway过滤器获取ResponseBody的值,查看了网上的帖子和官网内容:

    帖子:https://cloud.tencent.com/developer/article/1384111

    官网:https://github.com/spring-cloud/spring-cloud-gateway/blob/master/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyResponseBodyGatewayFilterFactory.java

    但在实际操作中却掉坑里了,居然不起作用,就是不进重写但writeWith方法

     1 @Component
     2 @Order(-2)
     3 public class EncryptResponseBodyFilter implements GlobalFilter {
     4 
     5     @Override
     6     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
     7         ServerHttpResponse originalResponse = exchange.getResponse();
     8         DataBufferFactory bufferFactory = originalResponse.bufferFactory();
     9         ServerHttpResponseDecorator response = new ServerHttpResponseDecorator(originalResponse) {
    10 
    11             @Override
    12             public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
    13                 if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
    14 
    15                     Flux<? extends DataBuffer> fluxBody = Flux.from(body);
    16                     return super.writeWith(fluxBody.map(dataBuffer -> {
    17                         // probably should reuse buffers
    18                         byte[] content = new byte[dataBuffer.readableByteCount()];
    19                         dataBuffer.read(content);
    20                         //释放掉内存
    21                         DataBufferUtils.release(dataBuffer);
    22                         String s = new String(content, Charset.forName("UTF-8"));
    23                         //TODO,s就是response的值,想修改、查看就随意而为了
    24                         byte[] uppedContent = s.getBytes();
    25                         return bufferFactory.wrap(uppedContent);
    26                     }));
    27                 }
    28                 return super.writeWith(body);
    29             }
    30 
    31             @Override
    32             public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
    33                 return writeWith(Flux.from(body)
    34                         .flatMapSequential(p -> p));
    35             }
    36         };37         return chain.filter(exchange.mutate().response(response).build());
    38     }

    后来与帖子和官网代码内容对比,只有Order的方式不同,就换了下实现Ordered重写getOrder方法方式试试,结果出乎意料,居然好用了!!!

    真的是绞尽脑汁啊,浪费了不少时间。。。。

    后来发现响应数据存在分段响应的问题:

    参考:https://blog.csdn.net/fayeyiwang/article/details/9137// JSON响应数据拼接容器

    private static Joiner joiner = Joiner.on("");
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        ServerHttpResponseDecorator response = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
                    // 获取ContentType,判断是否返回JSON格式数据
                    String originalResponseContentType = exchange.getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);
                    if(StringUtils.isNotBlank(originalResponseContentType) && originalResponseContentType.contains("application/json")) {
                       Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                       return super.writeWith(fluxBody.buffer().map(dataBuffers -> {//解决返回体分段传输
                          List<String> list = Lists.newArrayList();
                          dataBuffers.forEach(dataBuffer -> {
                             try {
                                byte[] content = new byte[dataBuffer.readableByteCount()];
                                dataBuffer.read(content);
                                DataBufferUtils.release(dataBuffer);
    
                                list.add(new String(content, "utf-8"));
                             } catch (Exception e) {
                                logger.info("动态加载API加密规则失败,失败原因:{}", Throwables.getStackTraceAsString(e));
                             }
                           });
                           String responseData = joiner.join(list);
                           // 二次处理(加密/过滤等)如果不需要做二次处理可直接跳过下行
                           responseData = beforeBodyWriteInternal(responseData, exchange.getRequest());
                           byte[] uppedContent = new String(responseData.getBytes(), Charset.forName("UTF-8")).getBytes();
                           originalResponse.getHeaders().setContentLength(uppedContent.length);
                           return bufferFactory.wrap(uppedContent);
                        }));
                     }
                }
                return super.writeWith(body);
            }
    
            @Override
            public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
                return writeWith(Flux.from(body).flatMapSequential(p -> p));
    } };
    return chain.filter(exchange.mutate().response(response).build());
    }
  • 相关阅读:
    Appium移动端UI自动化中,如果需要两个APP交互操作的实践经验
    基于Hibernate对Http接口进行全集测试实践
    Http自动跳转Https的接口测试实践
    PC端稳定性测试探索
    Batch脚本的简单应用
    Appium:中文输入的问题
    Android自动化:如何获取到APK安装包的Package以及Activity属性值
    收集一些深度学习视频
    1.1 摄像机的移动
    EF使用动态类型
  • 原文地址:https://www.cnblogs.com/commissar-Xia/p/11651196.html
Copyright © 2020-2023  润新知