获取SpringCloud gateway响应的response的值,记录踩坑
最近在做网关改造,想要通过Gateway过滤器获取ResponseBody的值,查看了网上的帖子和官网内容:
帖子:https://cloud.tencent.com/developer/article/1384111
但在实际操作中却掉坑里了,居然不起作用,就是不进重写但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()); }