获取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());
}

 使用过程期间发现,大数据量会存在字符切割问题,后改成下面逻辑解决:

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")) {
                        // 如果需要加密才进行处理
                        if (canEncrypt(exchange.getRequest())) {
                            Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                            return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                            	DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                                DataBuffer join = dataBufferFactory.join(dataBuffers);
                                byte[] content = new byte[join.readableByteCount()];
                                join.read(content);
                                DataBufferUtils.release(join);
                                String responseData = new String(content, Charsets.UTF_8);
//                                responseData = beforeBodyWriteInternal(responseData, exchange.getRequest());
                                responseData = "\"" + beforeBodyWriteInternal(responseData, exchange.getRequest()) + "\"";
                                byte[] uppedContent = new String(responseData.getBytes(), Charset.forName("UTF-8")).getBytes();
                                originalResponse.getHeaders().setContentLength(uppedContent.length);
                                // 设置加密头标识
                                originalResponse.getHeaders().set("encrypt", "true");
                                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());
    }

 

posted @ 2019-10-10 22:54  Commissar-Xia  阅读(24026)  评论(0编辑  收藏  举报