SpringCloud Gateway 网关获取或修改接口响应数据

news/2024/7/7 19:00:53 标签: spring cloud, gateway, spring

文章目录

    • 前言
    • 一、获取响应数据并打印

前言

      我们的网关在之前只记录了接口请求日志,响应日志是没有做记录的,在后续别人对接我们开放平台时出现了一些问题没法确认当时的一个数值状态,照成了很多不必要的麻烦,后来决定在网关添加上响应日志记录。

一、获取响应数据并打印

import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
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.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
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;

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

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        try {
            ServerHttpResponse originalResponse = exchange.getResponse();
            DataBufferFactory bufferFactory = originalResponse.bufferFactory();
            ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
                @Override
                public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                    if (body instanceof Flux) {
                        Flux<? extends DataBuffer> fluxBody = Flux.from(body);

                        return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                            // 合并多个流集合,解决返回体分段传输
                            DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                            DataBuffer buff = dataBufferFactory.join(dataBuffers);
                            byte[] content = new byte[buff.readableByteCount()];
                            buff.read(content);
                            DataBufferUtils.release(buff);//释放掉内存

                            //排除Excel导出,不是application/json不打印
                            MediaType contentType = originalResponse.getHeaders().getContentType();
                            if (!MediaType.APPLICATION_JSON.isCompatibleWith(contentType)) {
                                return bufferFactory.wrap(content);
                            }

                            // 想要关联请求和响应日志可以添加自定义请求头(我这里会在打印请求日志的过滤器中添加REUQEST_ID头来关联响应日志)
                            String reuqestId = exchange.getRequest().getHeaders().getFirst("REUQEST_ID");
                            // content就是response的值,可以查看和修改
                            String contentStr = new String(content, Charset.forName("UTF-8"));
                            log.info("reuqestId={} contentStr={}",reuqestId,contentStr);

                            getDelegate().getHeaders().setContentLength(contentStr.getBytes().length);
                            return bufferFactory.wrap(contentStr.getBytes());
                        }));
                    } else {
                        log.error("<-- {} 响应code异常", getStatusCode());
                    }
                    return super.writeWith(body);
                }
            };
            return chain.filter(exchange.mutate().response(decoratedResponse).build());

        } catch (Exception e) {
            log.error("gateway log exception e={}", e);
            return chain.filter(exchange);
        }
    }

    @Override
    public int getOrder() {
        return -1;
    }
}


http://www.niftyadmin.cn/n/5534905.html

相关文章

Flutter——最详细(Badge)使用教程

背景 主要常用于组件叠加上圆点提示&#xff1b; 使用场景&#xff0c;消息数量提示&#xff0c;消息红点提示 属性作用backgroundColor红点背景色smallSize设置红点大小isLabelVisible是否显示offset设置红点位置alignment设置红点位置child设置底部组件 代码块 class Badge…

复分析——第8章——共形映射(E.M. Stein R. Shakarchi)

第8章 共形映射(Conformal Mappings) The results I found for polygons can be extended under very general assumptions. I have undertaken this research because it is a step towards a deeper understanding of the mapping problem, for which not much has hap…

鸿蒙登录页面及页面跳转的设计

目录 任务目标任务分析任务实施1.新建工程项目HMLogin2.设计登录页面Index.visual3.设计第二个页面SecondPage4.修改Index.ets代码5.修改SecondPage.ets代码6.运行工程 任务目标 设计一个简单的登录页面&#xff0c;要求可以将第一页的登录信息&#xff0c;传递到第二个页面&a…

办公软件WPS与Office的区别

临近计算机考试很多同学在纠结我是报wps好&#xff1f;还是ms office好&#xff1f;下面就来详细说说。 1、wps属于国内金山公司的办公软件&#xff0c;里面包含word、Excel和PPT。考试是2021年开始的&#xff01; 2、MS&#xff08;Microsoft 微软&#xff09; office属于美…

【pytorch13】激活函数及梯度

什么是激活函数 计算机科学家借鉴生物的神经元机制发明了计算机上的模型&#xff0c;这个模型与生物的神经元非常类似 激活的意思就是z变量要大于0&#xff0c;这一个节点才会激活&#xff0c;否则就会处于睡眠状态不会输出电平值 该激活函数在z0处不可导&#xff0c;因此不能…

STM32工业自动化控制系统教程

目录 引言环境准备工业自动化控制系统基础代码实现&#xff1a;实现工业自动化控制系统 4.1 数据采集模块 4.2 数据处理与分析 4.3 控制系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;工业自动化与优化问题解决方案与优化收尾与总结 1. 引言 工业自动化控制系统利用…

MySQL之备份与恢复(四)

备份与恢复 存储引擎和一致性 3.复制 从备库中备份最大的好处是可以不干扰主库&#xff0c;避免在主库上增加额外的负载。这是一个建立备库的好理由&#xff0c;即使不需要用它做负载均衡或高可用。如果钱是个问题&#xff0c;也可以把备份用的备库用于其他用户&#xff0c;…

高级Redis之Stream的用法示例

不想自己搭建一个mq怎么办&#xff1f;Redis的Stream 来帮你&#xff0c;Redis Stream 是 Redis 5.0 引入的一种新的数据结构&#xff0c;用于处理实时的、可持久化的、基于时间序列的数据流。它非常适合处理事件流、日志、消息队列等场景。下面是一个使用 Redis Stream 的具体…