You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Cloud Gateway中如何记录请求URI、请求体及关联路由?

Spring Cloud Gateway 全局日志过滤器实现(记录URI、请求体及关联路由)

你的现有实现存在两个核心问题:一是读取请求体后没有重新包装,导致后续过滤器无法再读取请求体;二是过滤器执行顺序过早,还没完成路由匹配,所以拿不到关联的路由信息。以下是修正后的完整实现方案:

核心实现思路

  1. 控制过滤器执行顺序:确保在路由匹配完成后执行,通过实现Ordered接口指定优先级,顺序值需大于RouteToRequestUrlFilter的默认优先级(10000)。
  2. 缓存并复用请求体:由于Reactive场景下请求体数据流只能订阅一次,需读取后将内容缓存,并通过ServerHttpRequestDecorator重新包装请求,保证后续流程能正常读取。
  3. 获取匹配路由信息:从ServerWebExchange的属性中提取已匹配的路由对象,拿到路由ID和目标URI。

完整代码实现

import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
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.StandardCharsets;
import java.util.logging.Logger;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;

@Component
public class RequestLoggingFilter implements GlobalFilter, Ordered {

    private static final Logger logger = Logger.getLogger(RequestLoggingFilter.class.getName());
    // 优先级高于路由转发过滤器,确保已完成路由匹配
    private static final int FILTER_ORDER = 10001;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, org.springframework.cloud.gateway.filter.GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();

        // 获取已匹配的路由信息
        Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);

        // 记录请求基本信息和路由信息
        logger.info(String.format("Incoming request - URI: %s, Method: %s, Route ID: %s, Target URI: %s",
                request.getURI(), request.getMethod(), route.getId(), route.getUri()));

        // 仅对POST/PUT请求记录请求体
        if ("POST".equalsIgnoreCase(request.getMethodValue()) || "PUT".equalsIgnoreCase(request.getMethodValue())) {
            return DataBufferUtils.join(request.getBody())
                    .flatMap(dataBuffer -> {
                        // 缓存请求体字节数组
                        byte[] bodyBytes = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(bodyBytes);
                        DataBufferUtils.release(dataBuffer);

                        // 记录请求体
                        String requestBody = new String(bodyBytes, StandardCharsets.UTF_8);
                        logger.info("Request Body: " + requestBody);

                        // 重新包装请求,让后续过滤器能读取请求体
                        ServerHttpRequest decoratedRequest = new ServerHttpRequestDecorator(request) {
                            @Override
                            public Flux<DataBuffer> getBody() {
                                return Flux.defer(() -> {
                                    DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bodyBytes);
                                    DataBufferUtils.retain(buffer);
                                    return Mono.just(buffer);
                                });
                            }
                        };

                        // 继续执行过滤器链
                        return chain.filter(exchange.mutate().request(decoratedRequest).build());
                    });
        }

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return FILTER_ORDER;
    }
}

关键细节说明

  • 路由信息获取:通过GATEWAY_ROUTE_ATTR常量从exchange属性中获取已匹配的Route对象,能拿到路由ID、目标URI等核心信息。
  • 请求体重用:使用DataBufferUtils.join合并所有请求体缓冲块,读取后通过ServerHttpRequestDecorator重新生成请求体数据流,避免后续流程因数据流已被消费而报错。
  • 过滤器顺序:设置FILTER_ORDER = 10001,确保在RouteToRequestUrlFilter(order=10000)之后执行,此时路由匹配已完成,能正确获取路由信息。

注意事项

  • 大请求体处理:如果存在大文件上传等场景,直接缓存请求体到内存可能导致OOM,建议增加大小判断,超过阈值的请求体跳过记录。
  • 敏感信息过滤:日志中避免记录密码、令牌等敏感字段,可在记录前对请求体进行脱敏处理。
  • 日志级别调整:生产环境建议将日志级别从INFO改为DEBUG,避免过多日志输出影响性能。

内容的提问来源于stack exchange,提问作者milad sorour

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 03:37:21