Springcloudgateway如何在全局过滤器中获得请求体和响应体

需要使用请求装饰类和响应装饰类,把请求体和响应体保存一下,再在全局Post过滤器里面获得该请求体。

请求装饰类

java 复制代码
package com.chilun.apiopenspace.gateway.filter;

import com.chilun.apiopenspace.gateway.Utils.LogCacheMap;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
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.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;

import java.nio.charset.StandardCharsets;

/**
 * @author 齿轮
 * @date 2024-02-29-17:51
 */
@Slf4j
public class LoggingRequestDecorator extends ServerHttpRequestDecorator {
    private final String uuid;
    private final DataBufferFactory bufferFactory;

    public LoggingRequestDecorator(ServerHttpRequest delegate, ServerWebExchange exchange, String uuid) {
        super(delegate);
        this.bufferFactory = exchange.getResponse().bufferFactory();
        this.uuid = uuid;
    }

    @NotNull
    @Override
    public Flux<DataBuffer> getBody() {
        Flux<DataBuffer> originalBody = super.getBody();
        return originalBody.map(dataBuffer -> {
            byte[] content = new byte[dataBuffer.readableByteCount()];
            dataBuffer.read(content);
            // 将请求体数据转换为字符串,并保存到缓存中
            String requestBody = new String(content, StandardCharsets.UTF_8);
            log.info("Request Body: " + requestBody);
            LogCacheMap.saveRequest(uuid, requestBody);
            //重新包装了DataBuffer,所以要释放原始的DataBuffer
            DataBufferUtils.release(dataBuffer);
            // 返回新的DataBuffer
            return bufferFactory.wrap(content);
        });
    }
}

响应装饰类

java 复制代码
package com.chilun.apiopenspace.gateway.filter;

import com.chilun.apiopenspace.gateway.Utils.LogCacheMap;
import lombok.extern.slf4j.Slf4j;
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.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * @author 齿轮
 * @date 2024-02-29-17:51
 */
@Slf4j
public class LoggingResponseDecorator extends ServerHttpResponseDecorator {
    private final DataBufferFactory bufferFactory;
    private final String uuid;

    public LoggingResponseDecorator(ServerHttpResponse delegate, String uuid) {
        super(delegate);
        this.bufferFactory = delegate.bufferFactory();
        this.uuid = uuid;
    }

    @Override
    public Mono<Void> writeWith(org.reactivestreams.Publisher<? extends org.springframework.core.io.buffer.DataBuffer> body) {
//        if (getStatusCode().is2xxSuccessful()) {
//            //正常情况直接返回
//            return super.writeWith(body);
//        } else 
            if (body instanceof Flux) {
            //异常情况保存响应
            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 responseBody = new String(content, StandardCharsets.UTF_8);
                        log.info("response body: {}", responseBody);
                        LogCacheMap.saveResponse(uuid, responseBody);
                        byte[] uppedContent = responseBody.replaceAll(":null", ":\"\"").getBytes(StandardCharsets.UTF_8);
                        return bufferFactory.wrap(uppedContent);
                    }
            ));
        }
        return super.writeWith(body);
    }
}

用到的自定义工具类

java 复制代码
package com.chilun.apiopenspace.gateway.Utils;


import java.util.HashMap;

/**
 * @author 齿轮
 * @date 2024-02-29-18:52
 */

public class LogCacheMap {
    public static HashMap<String, String> LogMap = new HashMap<>();

    public static void saveRequest(String uuid, String request) {
        LogMap.put(uuid + "request", request);
    }

    public static String getRequest(String uuid) {
        return LogMap.remove(uuid + "request");
    }

    public static void saveResponse(String uuid, String response) {
        LogMap.put(uuid + "response", response);
    }

    public static String getResponse(String uuid) {
        return LogMap.remove(uuid + "response");
    }
}

全局过滤器类

java 复制代码
package com.chilun.apiopenspace.gateway.filter;

import com.chilun.apiopenspace.gateway.Utils.LogCacheMap;
import com.chilun.apiopenspace.gateway.service.AccessLogService;
import com.google.common.base.Joiner;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.UUID;

/**
 * @author 齿轮
 * @date 2024-02-28-14:35
 */
@Slf4j
@Component
public class LogFilter implements GlobalFilter, Ordered {
    @Resource
    AccessLogService logService;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String uuid = UUID.randomUUID().toString();

        //注入requestDecorator、responseDecorator用于获得请求体、响应体
        ServerHttpRequestDecorator requestDecorator = new LoggingRequestDecorator(exchange.getRequest(), exchange, uuid);
        ServerHttpResponseDecorator responseDecorator = new LoggingResponseDecorator(exchange.getResponse(), uuid);
        return chain.filter(exchange.mutate().request(requestDecorator).response(responseDecorator).build()).then(Mono.just(exchange))
                .map(serverWebExchange -> {
                    if (serverWebExchange.getResponse().getStatusCode().is2xxSuccessful()) {
                        logService.sendCommonLog(true);
                        logService.sendRightLog(LogCacheMap.getRequest(uuid), LogCacheMap.getResponse(uuid));

                    } else {
                        logService.sendCommonLog(false);
                        logService.sendErrorLog(LogCacheMap.getRequest(uuid), LogCacheMap.getResponse(uuid));
                    }
                    return serverWebExchange;
                })
                .then();
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

如果也是使用Map存储请求体,注意用不到请求体/响应体后删除他们,避免内存溢出。

相关推荐
andxe9 小时前
安科士 AndXe 技术博客:400G QSFP112 SR4 光模块|AI 算力与超算短距互联最优方案
网络·人工智能·光模块·光通信
shiyi.十一10 小时前
第2章:应用层 — 知识要点与架构
网络·计算机网络·架构
DFT计算杂谈10 小时前
无 Root 权限在 Tesla K80 零门槛部署 DeepSeek 大模型
linux·服务器·网络·数据库·机器学习
水境传感 李兆栋10 小时前
GNSS 位移监测站 :毫米级感知,筑牢安全监测防线
网络
中微极客12 小时前
2026主流AI Agent框架技术选型与性能对比
运维·网络·人工智能
REST_302714 小时前
告别Excel孤岛:一款任务链路可视化工具带来的真实改变
大数据·微服务·云计算·编辑器·excel·动态规划
beibeix201515 小时前
CppMicroServices 核心概念:动态服务注册与模块化系统
微服务·mitk
微三云 - 廖会灵 (私域系统开发)16 小时前
电商系统从单体到微服务拆分实践:拆什么、怎么拆、拆完后怎么办
微服务·云原生·架构
猿的天空16 小时前
机器人双手迎来全栈训练系统:灵初智能EgoSteer让灵巧手无所不能
网络·人工智能·计算机·ai·程序员·机器人·编程
Xzaveir_77716 小时前
OPPO、vivo、荣耀号码认证:多终端拨测矩阵与异常复现
大数据·网络·科技·矩阵·产品经理·ai-native