Skip to content

开发者指南

概述

Spring Cloud Gateway 是基于 Spring Boot 2.x、Spring WebFlux 和 Project Reactor 构建的微服务网关,它为微服务架构提供了简单、有效且统一的 API 路由管理方式。在实际业务场景中,我们经常需要自定义路由断言器(Route Predicate)、网关过滤器(Gateway Filter)和全局过滤器(Global Filter)来满足特定的业务需求。

本指南将帮助您理解如何编写 Spring Cloud Gateway 的自定义组件,包括路由断言器工厂、网关过滤器工厂和全局过滤器。

业务场景介绍

在微服务架构中,网关作为系统的入口,承担着重要的职责:

  • 统一认证授权:验证用户身份和权限
  • 请求路由分发:根据业务规则将请求路由到不同的微服务
  • 协议转换:HTTP/HTTPS、HTTP/2 等协议的转换
  • 监控和日志:记录请求响应信息,进行链路追踪
  • 限流熔断:保护后端服务不被过载

自定义路由断言器工厂(Route Predicate Factories)

什么是路由断言器

路由断言器用于判断传入的 HTTP 请求是否匹配特定的路由规则。Spring Cloud Gateway 内置了多种断言器,如路径匹配、请求头匹配、时间范围匹配等。但在实际业务中,我们可能需要根据特定的业务逻辑来创建自定义断言器。

实际应用场景

假设我们有一个电商系统,需要根据用户的会员等级来路由到不同的服务实例:

  • VIP 用户路由到高性能服务实例
  • 普通用户路由到标准服务实例

实现自定义路由断言器

kotlin
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate
import org.springframework.stereotype.Component
import org.springframework.web.server.ServerWebExchange
import java.util.function.Predicate

/**
 * 自定义用户等级路由断言器工厂
 * 根据用户等级决定是否匹配路由
 */
@Component
class UserLevelRoutePredicateFactory : AbstractRoutePredicateFactory<UserLevelRoutePredicateFactory.Config>(Config::class.java) {

    /**
     * 应用断言逻辑
     */
    override fun apply(config: Config): Predicate<ServerWebExchange> {
        return GatewayPredicate { exchange ->
            // 从请求中获取用户等级信息
            val request = exchange.request
            val userLevel = request.headers.getFirst("User-Level") ?: "NORMAL"

            // 根据配置的等级要求进行匹配
            when (config.requiredLevel) {
                "VIP" -> userLevel == "VIP" || userLevel == "SUPER_VIP"
                "NORMAL" -> userLevel == "NORMAL" || userLevel == "VIP" || userLevel == "SUPER_VIP"
                else -> false
            }
        }
    }

    /**
     * 配置类,定义断言器的配置属性
     */
    data class Config(
        var requiredLevel: String = "NORMAL" // 要求的用户等级
    )

    /**
     * 配置属性的快捷方式列表
     */
    override fun shortcutFieldOrder(): List<String> {
        return listOf("requiredLevel")
    }
}
java
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

/**
 * 自定义用户等级路由断言器工厂
 * 根据用户等级决定是否匹配路由
 */
@Component
public class UserLevelRoutePredicateFactory extends AbstractRoutePredicateFactory<UserLevelRoutePredicateFactory.Config> {

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

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return exchange -> {
            // 从请求中获取用户等级信息
            String userLevel = exchange.getRequest().getHeaders().getFirst("User-Level");
            if (userLevel == null) {
                userLevel = "NORMAL";
            }

            // 根据配置的等级要求进行匹配
            switch (config.getRequiredLevel()) {
                case "VIP":
                    return "VIP".equals(userLevel) || "SUPER_VIP".equals(userLevel);
                case "NORMAL":
                    return "NORMAL".equals(userLevel) || "VIP".equals(userLevel) || "SUPER_VIP".equals(userLevel);
                default:
                    return false;
            }
        };
    }

    /**
     * 配置类,定义断言器的配置属性
     */
    public static class Config {
        private String requiredLevel = "NORMAL"; // 要求的用户等级

        public String getRequiredLevel() {
            return requiredLevel;
        }

        public void setRequiredLevel(String requiredLevel) {
            this.requiredLevel = requiredLevel;
        }
    }

    /**
     * 配置属性的快捷方式列表
     */
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("requiredLevel");
    }
}

配置使用

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: vip-user-route
          uri: http://vip-service:8080
          predicates:
            - UserLevel=VIP # 使用自定义断言器
            - Path=/api/orders/**
        - id: normal-user-route
          uri: http://normal-service:8080
          predicates:
            - UserLevel=NORMAL
            - Path=/api/orders/**

断言器工厂类名必须以 `RoutePredicateFactory` 结尾,配置时使用类名的前缀部分。例如 `UserLevelRoutePredicateFactory` 在配置中使用 `UserLevel`。

自定义网关过滤器工厂(Gateway Filter Factories)

什么是网关过滤器

网关过滤器用于修改传入的 HTTP 请求和传出的 HTTP 响应。它们可以在请求被路由到下游服务之前(前置过滤器)或之后(后置过滤器)执行特定的逻辑。

实际应用场景

在实际业务中,我们可能需要:

  • 请求增强:添加链路追踪 ID、用户信息等
  • 请求验证:验证签名、检查参数合法性
  • 响应处理:统一响应格式、添加响应头
  • 监控统计:记录请求耗时、统计 API 调用次数

前置过滤器实现

前置过滤器在请求转发到下游服务之前执行,常用于请求预处理。

kotlin
import org.springframework.cloud.gateway.filter.GatewayFilter
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory
import org.springframework.stereotype.Component
import java.time.Instant
import java.util.*

/**
 * 请求增强过滤器工厂
 * 为请求添加追踪ID和时间戳
 */
@Component
class RequestEnhanceGatewayFilterFactory : AbstractGatewayFilterFactory<RequestEnhanceGatewayFilterFactory.Config>(Config::class.java) {

    override fun apply(config: Config): GatewayFilter {
        return GatewayFilter { exchange, chain ->
            // 生成唯一的请求追踪ID
            val traceId = UUID.randomUUID().toString().replace("-", "")
            val timestamp = Instant.now().toString()

            // 构建修改后的请求
            val request = exchange.request.mutate()
                .header("X-Trace-Id", traceId)               // 添加追踪ID
                .header("X-Request-Time", timestamp)         // 添加请求时间
                .header("X-Gateway-Version", config.version) // 添加网关版本信息
                .build()

            // 记录请求信息到日志
            println("Request enhanced: traceId=$traceId, path=${request.path}, method=${request.method}")

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

    /**
     * 配置类
     */
    data class Config(
        var version: String = "1.0.0" // 网关版本信息
    )

    /**
     * 配置属性的快捷方式列表
     */
    override fun shortcutFieldOrder(): List<String> {
        return listOf("version")
    }
}
java
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.time.Instant;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/**
 * 请求增强过滤器工厂
 * 为请求添加追踪ID和时间戳
 */
@Component
public class RequestEnhanceGatewayFilterFactory extends AbstractGatewayFilterFactory<RequestEnhanceGatewayFilterFactory.Config> {

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

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            // 生成唯一的请求追踪ID
            String traceId = UUID.randomUUID().toString().replace("-", "");
            String timestamp = Instant.now().toString();

            // 构建修改后的请求
            ServerHttpRequest request = exchange.getRequest().mutate()
                    .header("X-Trace-Id", traceId)               // 添加追踪ID
                    .header("X-Request-Time", timestamp)         // 添加请求时间
                    .header("X-Gateway-Version", config.getVersion()) // 添加网关版本信息
                    .build();

            // 记录请求信息到日志
            System.out.println("Request enhanced: traceId=" + traceId +
                             ", path=" + request.getPath() +
                             ", method=" + request.getMethod());

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

    /**
     * 配置类
     */
    public static class Config {
        private String version = "1.0.0"; // 网关版本信息

        public String getVersion() {
            return version;
        }

        public void setVersion(String version) {
            this.version = version;
        }
    }

    /**
     * 配置属性的快捷方式列表
     */
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("version");
    }
}

后置过滤器实现

后置过滤器在下游服务返回响应后执行,常用于响应后处理。

kotlin
import org.springframework.cloud.gateway.filter.GatewayFilter
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory
import org.springframework.stereotype.Component
import reactor.core.publisher.Mono

/**
 * 响应处理过滤器工厂
 * 统一处理响应头和响应格式
 */
@Component
class ResponseProcessGatewayFilterFactory : AbstractGatewayFilterFactory<ResponseProcessGatewayFilterFactory.Config>(Config::class.java) {

    override fun apply(config: Config): GatewayFilter {
        return GatewayFilter { exchange, chain ->
            chain.filter(exchange).then(Mono.fromRunnable {
                val response = exchange.response

                // 添加自定义响应头
                response.headers.add("X-Response-From", "Spring Cloud Gateway")
                response.headers.add("X-Response-Time", System.currentTimeMillis().toString())
                response.headers.add("X-Service-Version", config.serviceVersion)

                // 根据响应状态添加不同的处理逻辑
                val statusCode = response.statusCode
                when {
                    statusCode?.is2xxSuccessful == true -> {
                        response.headers.add("X-Response-Status", "SUCCESS")
                        println("Response processed successfully: ${statusCode.value()}")
                    }
                    statusCode?.is4xxClientError == true -> {
                        response.headers.add("X-Response-Status", "CLIENT_ERROR")
                        println("Client error occurred: ${statusCode.value()}")
                    }
                    statusCode?.is5xxServerError == true -> {
                        response.headers.add("X-Response-Status", "SERVER_ERROR")
                        println("Server error occurred: ${statusCode.value()}")
                    }
                }
            })
        }
    }

    /**
     * 配置类
     */
    data class Config(
        var serviceVersion: String = "1.0.0" // 服务版本信息
    )

    /**
     * 配置属性的快捷方式列表
     */
    override fun shortcutFieldOrder(): List<String> {
        return listOf("serviceVersion")
    }
}
java
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.List;

/**
 * 响应处理过滤器工厂
 * 统一处理响应头和响应格式
 */
@Component
public class ResponseProcessGatewayFilterFactory extends AbstractGatewayFilterFactory<ResponseProcessGatewayFilterFactory.Config> {

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

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                ServerHttpResponse response = exchange.getResponse();

                // 添加自定义响应头
                response.getHeaders().add("X-Response-From", "Spring Cloud Gateway");
                response.getHeaders().add("X-Response-Time", String.valueOf(System.currentTimeMillis()));
                response.getHeaders().add("X-Service-Version", config.getServiceVersion());

                // 根据响应状态添加不同的处理逻辑
                HttpStatus statusCode = response.getStatusCode();
                if (statusCode != null) {
                    if (statusCode.is2xxSuccessful()) {
                        response.getHeaders().add("X-Response-Status", "SUCCESS");
                        System.out.println("Response processed successfully: " + statusCode.value());
                    } else if (statusCode.is4xxClientError()) {
                        response.getHeaders().add("X-Response-Status", "CLIENT_ERROR");
                        System.out.println("Client error occurred: " + statusCode.value());
                    } else if (statusCode.is5xxServerError()) {
                        response.getHeaders().add("X-Response-Status", "SERVER_ERROR");
                        System.out.println("Server error occurred: " + statusCode.value());
                    }
                }
            }));
        };
    }

    /**
     * 配置类
     */
    public static class Config {
        private String serviceVersion = "1.0.0"; // 服务版本信息

        public String getServiceVersion() {
            return serviceVersion;
        }

        public void setServiceVersion(String serviceVersion) {
            this.serviceVersion = serviceVersion;
        }
    }

    /**
     * 配置属性的快捷方式列表
     */
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("serviceVersion");
    }
}

配置使用

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: enhanced-route
          uri: http://backend-service:8080
          predicates:
            - Path=/api/**
          filters:
            - RequestEnhance=2.0.0 # 使用自定义前置过滤器
            - ResponseProcess=1.5.0 # 使用自定义后置过滤器

过滤器命名规范

自定义过滤器类名必须以 `GatewayFilterFactory` 结尾。例如,要在配置中引用名为 `Something` 的过滤器,过滤器类必须命名为 `SomethingGatewayFilterFactory`。

虽然可以创建不以 `GatewayFilterFactory` 结尾的过滤器类(如 `class AnotherThing`),并在配置文件中引用为 `AnotherThing`,但这不是支持的命名约定,这种语法可能在未来的版本中被移除。

自定义全局过滤器(Global Filters)

什么是全局过滤器

全局过滤器会应用于所有的路由,无需在具体路由配置中声明。它们通常用于实现跨切面的功能,如认证、授权、监控、日志记录等。

实际应用场景

全局过滤器的典型应用场景包括:

  • 统一认证授权:验证 JWT 令牌、检查用户权限
  • API 限流:防止系统过载
  • 链路追踪:记录请求链路信息
  • 性能监控:统计请求响应时间

实现全局过滤器

kotlin
import org.springframework.cloud.gateway.filter.GlobalFilter
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.Ordered
import org.springframework.http.HttpStatus
import org.springframework.http.server.reactive.ServerHttpRequest
import reactor.core.publisher.Mono
import java.security.Principal
import java.time.Instant

/**
 * 全局过滤器配置类
 */
@Configuration
class GlobalFilterConfig {

    /**
     * 自定义全局前置过滤器
     * 用于统一认证和请求预处理
     */
    @Bean
    fun customGlobalFilter(): GlobalFilter {
        return GlobalFilter { exchange, chain ->
            val startTime = System.currentTimeMillis()

            // 获取用户信息并添加到请求头
            exchange.getPrincipal<Principal>()
                .map { it.name }
                .defaultIfEmpty("Anonymous")
                .map { userName ->
                    // 构建增强的请求
                    val requestBuilder = exchange.request.mutate()
                        .header("X-User-Name", userName)           // 添加用户名
                        .header("X-Request-Start-Time", startTime.toString()) // 添加请求开始时间
                        .header("X-Gateway-Instance", "gateway-01") // 添加网关实例标识

                    // 记录请求日志
                    val request = exchange.request
                    println("Global Filter - Request: ${request.method} ${request.path} from $userName")

                    // 构建新的交换对象
                    exchange.mutate().request(requestBuilder.build()).build()
                }
                .flatMap { enhancedExchange ->
                    // 继续执行过滤器链
                    chain.filter(enhancedExchange)
                        .doFinally {
                            // 计算并记录请求耗时
                            val endTime = System.currentTimeMillis()
                            val duration = endTime - startTime
                            println("Global Filter - Request completed in ${duration}ms")
                        }
                }
        }
    }

    /**
     * 自定义全局后置过滤器
     * 用于统一响应处理和监控
     */
    @Bean
    fun customGlobalPostFilter(): GlobalFilter {
        return GlobalFilter { exchange, chain ->
            chain.filter(exchange)
                .then(Mono.just(exchange))
                .map { serverWebExchange ->
                    val response = serverWebExchange.response
                    val request = serverWebExchange.request

                    // 添加响应头
                    response.headers.set("X-Response-From-Gateway", "true")
                    response.headers.set("X-Response-Timestamp", Instant.now().toString())

                    // 根据响应状态设置不同的响应头
                    val statusCode = response.statusCode
                    val statusMessage = when {
                        statusCode?.equals(HttpStatus.OK) == true -> "Success"
                        statusCode?.is4xxClientError == true -> "Client Error"
                        statusCode?.is5xxServerError == true -> "Server Error"
                        else -> "Unknown"
                    }

                    response.headers.set("X-Response-Status-Message", statusMessage)

                    // 记录响应日志
                    println("Global Post Filter - Response: ${statusCode?.value()} for ${request.path}")

                    serverWebExchange
                }
                .then()
        }
    }

    /**
     * 带优先级的全局过滤器
     * 实现 Ordered 接口来控制执行顺序
     */
    @Bean
    fun highPriorityGlobalFilter(): GlobalFilter {
        return object : GlobalFilter, Ordered {
            override fun filter(exchange: org.springframework.web.server.ServerWebExchange, chain: org.springframework.cloud.gateway.filter.GatewayFilterChain): Mono<Void> {
                // 高优先级的预处理逻辑
                println("High Priority Global Filter - Before request processing")

                return chain.filter(exchange)
                    .doFinally {
                        println("High Priority Global Filter - After request processing")
                    }
            }

            override fun getOrder(): Int {
                return -1 // 较小的数值表示较高的优先级
            }
        }
    }
}
java
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.security.Principal;
import java.time.Instant;

/**
 * 全局过滤器配置类
 */
@Configuration
public class GlobalFilterConfig {

    /**
     * 自定义全局前置过滤器
     * 用于统一认证和请求预处理
     */
    @Bean
    public GlobalFilter customGlobalFilter() {
        return (exchange, chain) -> {
            long startTime = System.currentTimeMillis();

            // 获取用户信息并添加到请求头
            return exchange.getPrincipal(Principal.class)
                    .map(Principal::getName)
                    .defaultIfEmpty("Anonymous")
                    .map(userName -> {
                        // 构建增强的请求
                        ServerHttpRequest request = exchange.getRequest().mutate()
                                .header("X-User-Name", userName)           // 添加用户名
                                .header("X-Request-Start-Time", String.valueOf(startTime)) // 添加请求开始时间
                                .header("X-Gateway-Instance", "gateway-01") // 添加网关实例标识
                                .build();

                        // 记录请求日志
                        System.out.println("Global Filter - Request: " + request.getMethod() +
                                         " " + request.getPath() + " from " + userName);

                        // 构建新的交换对象
                        return exchange.mutate().request(request).build();
                    })
                    .flatMap(enhancedExchange -> {
                        // 继续执行过滤器链
                        return chain.filter(enhancedExchange)
                                .doFinally(signalType -> {
                                    // 计算并记录请求耗时
                                    long endTime = System.currentTimeMillis();
                                    long duration = endTime - startTime;
                                    System.out.println("Global Filter - Request completed in " + duration + "ms");
                                });
                    });
        };
    }

    /**
     * 自定义全局后置过滤器
     * 用于统一响应处理和监控
     */
    @Bean
    public GlobalFilter customGlobalPostFilter() {
        return (exchange, chain) -> {
            return chain.filter(exchange)
                    .then(Mono.just(exchange))
                    .map(serverWebExchange -> {
                        ServerHttpResponse response = serverWebExchange.getResponse();
                        ServerHttpRequest request = serverWebExchange.getRequest();

                        // 添加响应头
                        response.getHeaders().set("X-Response-From-Gateway", "true");
                        response.getHeaders().set("X-Response-Timestamp", Instant.now().toString());

                        // 根据响应状态设置不同的响应头
                        HttpStatus statusCode = response.getStatusCode();
                        String statusMessage;
                        if (HttpStatus.OK.equals(statusCode)) {
                            statusMessage = "Success";
                        } else if (statusCode != null && statusCode.is4xxClientError()) {
                            statusMessage = "Client Error";
                        } else if (statusCode != null && statusCode.is5xxServerError()) {
                            statusMessage = "Server Error";
                        } else {
                            statusMessage = "Unknown";
                        }

                        response.getHeaders().set("X-Response-Status-Message", statusMessage);

                        // 记录响应日志
                        System.out.println("Global Post Filter - Response: " +
                                         (statusCode != null ? statusCode.value() : "null") +
                                         " for " + request.getPath());

                        return serverWebExchange;
                    })
                    .then();
        };
    }

    /**
     * 带优先级的全局过滤器
     * 实现 Ordered 接口来控制执行顺序
     */
    @Bean
    public GlobalFilter highPriorityGlobalFilter() {
        return new GlobalFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, org.springframework.cloud.gateway.filter.GatewayFilterChain chain) {
                // 高优先级的预处理逻辑
                System.out.println("High Priority Global Filter - Before request processing");

                return chain.filter(exchange)
                        .doFinally(signalType -> {
                            System.out.println("High Priority Global Filter - After request processing");
                        });
            }

            @Override
            public int getOrder() {
                return -1; // 较小的数值表示较高的优先级
            }
        };
    }
}

过滤器执行顺序

全局过滤器的执行顺序可以通过实现 `Ordered` 接口的 `getOrder()` 方法来控制。数值越小,优先级越高。

实际业务案例:构建企业级 API 网关

让我们通过一个完整的企业级案例来展示如何组合使用这些自定义组件。

场景描述

假设我们正在为一家电商公司构建 API 网关,需要满足以下需求:

  1. 用户等级路由:VIP 用户访问高性能服务实例
  2. API 认证:验证 API 密钥和用户权限
  3. 请求限流:防止系统过载
  4. 链路追踪:记录完整的请求链路
  5. 响应统一:统一 API 响应格式

完整配置示例

yaml
# application.yml
spring:
  cloud:
    gateway:
      routes:
        # VIP用户路由配置
        - id: vip-order-service
          uri: http://vip-order-service:8080
          predicates:
            - UserLevel=VIP
            - Path=/api/orders/**
          filters:
            - RequestEnhance=2.0.0
            - ResponseProcess=1.5.0
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 100
                redis-rate-limiter.burstCapacity: 200

        # 普通用户路由配置
        - id: normal-order-service
          uri: http://normal-order-service:8080
          predicates:
            - UserLevel=NORMAL
            - Path=/api/orders/**
          filters:
            - RequestEnhance=2.0.0
            - ResponseProcess=1.5.0
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 50
                redis-rate-limiter.burstCapacity: 100

        # 用户服务路由
        - id: user-service
          uri: http://user-service:8080
          predicates:
            - Path=/api/users/**
          filters:
            - RequestEnhance=2.0.0
            - ResponseProcess=1.5.0

# 全局配置
management:
  endpoints:
    web:
      exposure:
        include: gateway,health,info
  endpoint:
    gateway:
      enabled: true

logging:
  level:
    org.springframework.cloud.gateway: DEBUG
    com.yourcompany.gateway: DEBUG

监控和指标

为了更好地监控网关性能,我们可以添加指标收集:

kotlin
import io.micrometer.core.instrument.MeterRegistry
import io.micrometer.core.instrument.Timer
import org.springframework.cloud.gateway.filter.GlobalFilter
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.Ordered
import reactor.core.publisher.Mono

/**
 * 指标收集全局过滤器
 */
@Configuration
class MetricsGlobalFilter(private val meterRegistry: MeterRegistry) {

    @Bean
    fun metricsGlobalFilter(): GlobalFilter {
        return object : GlobalFilter, Ordered {
            override fun filter(exchange: org.springframework.web.server.ServerWebExchange,
                              chain: org.springframework.cloud.gateway.filter.GatewayFilterChain): Mono<Void> {

                val startTime = System.nanoTime()
                val request = exchange.request
                val path = request.path.value()
                val method = request.method?.name ?: "UNKNOWN"

                return chain.filter(exchange)
                    .doFinally {
                        val duration = System.nanoTime() - startTime
                        val response = exchange.response
                        val statusCode = response.statusCode?.value()?.toString() ?: "unknown"

                        // 记录请求计数
                        meterRegistry.counter("gateway.requests.total",
                            "method", method,
                            "path", path,
                            "status", statusCode
                        ).increment()

                        // 记录请求耗时
                        Timer.Sample.start(meterRegistry)
                            .stop(Timer.builder("gateway.request.duration")
                                .tag("method", method)
                                .tag("path", path)
                                .tag("status", statusCode)
                                .register(meterRegistry))
                    }
            }

            override fun getOrder(): Int = Ordered.HIGHEST_PRECEDENCE + 1
        }
    }
}
java
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 指标收集全局过滤器
 */
@Configuration
public class MetricsGlobalFilter {

    private final MeterRegistry meterRegistry;

    public MetricsGlobalFilter(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }

    @Bean
    public GlobalFilter metricsGlobalFilter() {
        return new GlobalFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange,
                                   org.springframework.cloud.gateway.filter.GatewayFilterChain chain) {

                long startTime = System.nanoTime();
                ServerHttpRequest request = exchange.getRequest();
                String path = request.getPath().value();
                String method = request.getMethod() != null ? request.getMethod().name() : "UNKNOWN";

                return chain.filter(exchange)
                        .doFinally(signalType -> {
                            long duration = System.nanoTime() - startTime;
                            ServerHttpResponse response = exchange.getResponse();
                            String statusCode = response.getStatusCode() != null ?
                                              String.valueOf(response.getStatusCode().value()) : "unknown";

                            // 记录请求计数
                            meterRegistry.counter("gateway.requests.total",
                                    "method", method,
                                    "path", path,
                                    "status", statusCode
                            ).increment();

                            // 记录请求耗时
                            Timer.builder("gateway.request.duration")
                                    .tag("method", method)
                                    .tag("path", path)
                                    .tag("status", statusCode)
                                    .register(meterRegistry)
                                    .record(duration, java.util.concurrent.TimeUnit.NANOSECONDS);
                        });
            }

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

最佳实践和注意事项

🎯 性能优化建议

TIP

  1. 避免阻塞操作:在过滤器中使用响应式编程,避免阻塞操作
  2. 合理设置过滤器顺序:通过 Ordered 接口控制执行顺序
  3. 资源清理:及时释放不需要的资源,避免内存泄漏
  4. 异常处理:妥善处理异常,避免影响整个请求链路

⚠️ 常见陷阱

WARNING

  1. 过滤器命名:必须严格遵循命名规范,以 GatewayFilterFactory 结尾
  2. 配置类型:确保配置类的属性类型与配置文件中的值匹配
  3. 内存使用:避免在过滤器中保存大量状态信息
  4. 日志级别:生产环境中适当调整日志级别,避免性能影响

🔧 调试技巧

启用 Gateway 调试日志来排查问题:

yaml
logging:
  level:
    org.springframework.cloud.gateway: DEBUG
    org.springframework.web.server.adapter.HttpWebHandlerAdapter: DEBUG

总结

通过本指南,我们学习了如何在 Spring Cloud Gateway 中:

  1. 创建自定义路由断言器:根据业务规则判断请求是否匹配特定路由
  2. 实现自定义网关过滤器:在请求前后执行特定的业务逻辑
  3. 开发全局过滤器:实现跨所有路由的统一功能
  4. 构建企业级解决方案:组合使用多种组件解决实际业务问题

这些自定义组件为我们提供了强大的扩展能力,使得 Spring Cloud Gateway 能够适应各种复杂的业务场景。在实际开发中,建议根据具体需求选择合适的扩展方式,并充分考虑性能、可维护性和可扩展性。

Details

参考资源