Spring Cloud之服务入口Gateway之自定义过滤器

Spring Cloud Gateway 之服务入口 — 自定义过滤器详解
(基于 Spring Cloud 2024.x / 2025.x 主流版本,2026年3月视角)

Spring Cloud Gateway 是目前最主流的第二代网关(非 Zuul),其过滤器机制是核心扩展点,几乎所有鉴权、日志、限流、请求/响应改写、灰度、WAF 等功能都靠自定义过滤器实现。

一、Gateway 过滤器三大类型对比(必背)

类型作用范围配置方式是否需要 Ordered典型使用场景实现接口/基类
GlobalFilter全局(所有路由)@Component / @Bean是(强烈推荐)统一鉴权、日志、跨域、请求ID追踪、限流兜底GlobalFilter + Ordered
GatewayFilter单路由 / 部分路由yml routes.filters 或 default-filters是(通过 OrderedGatewayFilter 包装)路由级别的特殊处理(如特定接口加 header)AbstractGatewayFilterFactory → apply() 返回 GatewayFilter
GatewayFilterFactory可配置参数的路由级过滤器yml 中以 – Name=xxx,xxx 写法可选最常用:带参数的复用过滤器(如 AddHeader、限流、脱敏)AbstractGatewayFilterFactory

2026年推荐优先级

  1. 需要全局统一处理 → GlobalFilter
  2. 需要带参数、路由级别复用 → 自定义 GatewayFilterFactory(最灵活)
  3. 极少数场景才直接手写 GatewayFilter(不带工厂)

二、最常用写法:自定义 GlobalFilter(全局鉴权 / 日志 / 请求追踪)

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.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.UUID;

@Component
public class RequestIdGlobalFilter implements GlobalFilter, Ordered {

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

        // 1. 前置处理(pre filter)
        String requestId = request.getHeaders().getFirst("X-Request-Id");
        if (requestId == null) {
            requestId = UUID.randomUUID().toString().replace("-", "");
        }

        // 放入 MDC 或 exchange 属性,供下游使用
        exchange.getAttributes().put("X-Request-Id", requestId);

        // 可记录开始时间
        long startTime = System.currentTimeMillis();

        // 2. 继续过滤链(相当于 chain.doFilter)
        return chain.filter(exchange)
                // 3. 后置处理(post filter)
                .doFinally(signalType -> {
                    long cost = System.currentTimeMillis() - startTime;
                    // 可记录日志:请求路径、耗时、状态码等
                    System.out.printf("[Gateway] %s %s cost=%dms%n",
                            request.getMethod(), request.getURI(), cost);
                });
    }

    /**
     * 过滤器执行顺序:值越小越先执行
     * 常见参考值:
     * - NettyWriteResponseFilter = -1(写响应)
     * - LoadBalancerClientFilter ≈ 10100(负载均衡)
     * 建议:鉴权/日志放 -100 ~ 100 区间
     */
    @Override
    public int getOrder() {
        return -100;
    }
}

三、最灵活写法:自定义 GatewayFilterFactory(带配置参数)

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

@Component
public class AddCustomHeaderGatewayFilterFactory 
        extends AbstractGatewayFilterFactory<AddCustomHeaderGatewayFilterFactory.Config> {

    public AddCustomHeaderGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest req = exchange.getRequest().mutate()
                    .header(config.getHeaderName(), config.getHeaderValue())
                    .build();

            return chain.filter(exchange.mutate().request(req).build());
        };
    }

    @Override
    public List<String> shortcutFieldOrder() {
        // 快捷写法支持: - AddCustomHeader=X-Trace-Id, ${traceId}
        return Arrays.asList("headerName", "headerValue");
    }

    public static class Config {
        private String headerName;
        private String headerValue;

        // getter & setter
        public String getHeaderName() { return headerName; }
        public void setHeaderName(String headerName) { this.headerName = headerName; }
        public String getHeaderValue() { return headerValue; }
        public void setHeaderValue(String headerValue) { this.headerValue = headerValue; }
    }
}

yml 配置方式(三种等价写法):

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/user/**
          filters:
            # 方式1:完整类名(不推荐)
            # - name: AddCustomHeaderGatewayFilterFactory
            #   args:
            #     headerName: X-Trace-Id
            #     headerValue: trace-${traceId}

            # 方式2:简写(推荐,类名去掉 GatewayFilterFactory 后缀)
            - AddCustomHeader=X-Trace-Id, trace-${traceId}

            # 方式3:带参数的工厂写法
            # - name: AddCustomHeader
            #   args:
            #     headerName: X-From
            #     headerValue: gateway

四、常见应用场景 & 推荐顺序值参考(2026主流)

场景推荐类型建议 order 值说明
请求ID生成/追踪GlobalFilter-200 ~ -100最早放,便于全链路追踪
统一鉴权/JWT校验GlobalFilter-50 ~ 0在路由匹配后、转发前
限流/熔断GatewayFilterFactory100 ~ 200可针对路由精细控制
请求/响应日志GlobalFilter-150 / 900pre 记录开始,post 记录结束+耗时
添加/脱敏 HeaderGatewayFilterFactory300 ~ 500可配置化
响应包装/统一格式GlobalFilter900 ~ -2晚于 -1(Netty写响应前)
CORS 跨域GlobalFilter 或内置-300通常用 CorsWebFilter 或自定义

五、2026年避坑 & 最佳实践

  1. 顺序混乱 → 导致鉴权没生效、header没加 → 一定要实现 Ordered 并合理赋值
  2. 阻塞操作 → 禁止在 filter 里用 Thread.sleep、JDBC、同步HTTP → 用 Mono/Flux 异步
  3. 重复读取 body → 需要缓存请求体用 ServerWebExchangeDecorator + modifyRequestBody
  4. 生产关闭调试日志 → logging.level.org.springframework.cloud.gateway=INFO
  5. 优先使用内置过滤器 → RewritePath、AddRequestHeader、RequestRateLimiter、Retry 等
  6. 异步友好 → 所有自定义 filter 都返回 Mono,避免 blocking

你现在想实现哪种具体过滤器?

  • JWT / Token 统一校验
  • 请求响应全链路日志 + traceId
  • 响应体统一包装(类似 R)
  • IP 黑白名单 / 限流
  • Header 参数脱敏 / 添加签名

告诉我场景 + 需求,我直接给你完整可运行代码(包括 yml 配置 + 测试方式)。

文章已创建 4915

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部