当前位置: 首页 > news >正文

SpringCloud GateWay 网关 在GlobalFilter 拿出返回数据response

前言

文章主旨:   将返回数据拿出来,然后各种处理。

正文
 

先看该篇文章的示例接口:

红色框框里面就是返回的 response 数据 。

现在我们想要的就是 在返回给到调用方(前端、第三方等)前,我们抓出来数据,随便改一下东西。

例如: 我要把里面的message 提示语改了。

新建一个全局过滤器:

WrapperResponseGlobalFilter.java

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Joiner;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.nio.charset.Charset;
import java.util.List;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR;

/**
 * @Author JCccc
 * @Description 拦截返回数据, 修改返回数据
 * @Date 2021/8/16 19:22
 */

@Component
public class WrapperResponseGlobalFilter implements GlobalFilter, Ordered {

    private static final Logger log = LoggerFactory.getLogger(WrapperResponseGlobalFilter.class);

    @Override
    public int getOrder() {
        // -1 is response write filter, must be called before that
        return -2;
    }

    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) {
                                    log.info("加载Response字节流异常,失败原因:{}", Throwables.getStackTraceAsString(e));
                                }
                            });
                            String responseData = joiner.join(list);

                            
                            System.out.println("responseData:"+responseData);

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


}

调用接口可以看到,response数据已经被我们拎出来了:

那么我们简单做个处理,

 

    /**
     * 返回数据处理
     *
     * @param responseData
     * @return
     */
    private String responseHandle(String responseData) {
        String responseResultJson = null;
        try {
            JSONObject jsonObject = JSONObject.parseObject(responseData);
            jsonObject.put("message", "JCccc 收藏+关注");
            responseResultJson = jsonObject.toJSONString();
        } catch (Exception e) {
            log.info("返回数据处理转化失败,异常信息={}",e.getMessage());
            return responseData;
        }
        return responseResultJson;
    }

再次请求,可以看到:


返回数据里面的message已经被我们修改成功了

PS:

还有类似,既然个人信息这么敏感,是不是类似一些接口返回数据需要做统一的加密呢? 

如需要,那么也可以通过配置化读取需要加密的ur列表,然后通过exchange把url拿出来做匹对,对responseData  做加密处理。

ServerHttpRequest request = exchange.getRequest();
URI url = request.getURI();
String urlPath = url.getPath();
System.out.println("当前请求url是:"+urlPath);

好了,该篇就到这。

相关文章:

  • java 获取IP地址 无法获取到真实的IP地址
  • Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)
  • Java 将两个对象list里面的 某个字段值抽取到一个list里
  • Springboot 整合 WebSocket ,使用STOMP协议+Redis 解决负载场景问题(二)
  • Springboot 使用 Guava 的重试Retry ,轻便灵活
  • Springboot Async异步扩展使用 结合 CompletableFuture
  • Springboot Condition 实用讲解,只看一遍包学会
  • 聊点不一样的,初级软件测试岗需要做些什么?
  • 聊一聊多线程的 run() 和 start(),挖一挖start0
  • JAVA 继承Thread 实现多线程 资源不共享? 请保持清醒 。
  • SpringBoot 事件发布监听机制使用、分析、注意点 (一篇到位)
  • Springboot yml配置参数数据加密 (数据加密篇 一)
  • Springboot AOP实现指定敏感字段数据加密 (数据加密篇 二)
  • Springboot 使用mysql加密解密函数 (数据加密篇 三)
  • Java List数据量大, 需要分片批次操作
  • 2017 前端面试准备 - 收藏集 - 掘金
  • ES6简单总结(搭配简单的讲解和小案例)
  • exports和module.exports
  • JavaScript中的对象个人分享
  • Java读取Properties文件的六种方法
  • JSONP原理
  • Koa2 之文件上传下载
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • Spring-boot 启动时碰到的错误
  • 构建二叉树进行数值数组的去重及优化
  • 精彩代码 vue.js
  • 每天一个设计模式之命令模式
  • 前嗅ForeSpider采集配置界面介绍
  • 山寨一个 Promise
  • 深入浅出Node.js
  • 主流的CSS水平和垂直居中技术大全
  • 带你开发类似Pokemon Go的AR游戏
  • # include “ “ 和 # include < >两者的区别
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • #在 README.md 中生成项目目录结构
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (6)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—使用Adaboost建模及工作环境下的数据分析整理
  • (Python第六天)文件处理
  • (pytorch进阶之路)CLIP模型 实现图像多模态检索任务
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (机器学习-深度学习快速入门)第一章第一节:Python环境和数据分析
  • (四)Linux Shell编程——输入输出重定向
  • (转载)Google Chrome调试JS
  • .md即markdown文件的基本常用编写语法
  • .net 4.0 A potentially dangerous Request.Form value was detected from the client 的解决方案
  • .NET的数据绑定
  • /bin/bash^M: bad interpreter: No such file or directory
  • @converter 只能用mysql吗_python-MySQLConverter对象没有mysql-connector属性’...
  • @zabbix数据库历史与趋势数据占用优化(mysql存储查询)
  • [ 第一章] JavaScript 简史
  • [20171113]修改表结构删除列相关问题4.txt