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存储请求体,注意用不到请求体/响应体后删除他们,避免内存溢出。

相关推荐
新手小袁_J3 分钟前
JDK11下载安装和配置超详细过程
java·spring cloud·jdk·maven·mybatis·jdk11
m0_7482400223 分钟前
Chromium 中chrome.webRequest扩展接口定义c++
网络·c++·chrome
終不似少年遊*31 分钟前
华为云计算HCIE笔记05
网络·华为云·云计算·学习笔记·hcie·认证·hcs
蜜獾云44 分钟前
docker 安装雷池WAF防火墙 守护Web服务器
linux·运维·服务器·网络·网络安全·docker·容器
小林熬夜学编程2 小时前
【Linux网络编程】第十四弹---构建功能丰富的HTTP服务器:从状态码处理到服务函数扩展
linux·运维·服务器·c语言·网络·c++·http
Hacker_Fuchen2 小时前
天融信网络架构安全实践
网络·安全·架构
上海运维Q先生2 小时前
面试题整理15----K8s常见的网络插件有哪些
运维·网络·kubernetes
ProtonBase2 小时前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构
fantasy_arch12 小时前
CPU性能优化-磁盘空间和解析时间
网络·性能优化
Java程序之猿12 小时前
微服务分布式(一、项目初始化)
分布式·微服务·架构