Skip to content

网关配置

Spring Cloud Gateway 是基于 Spring WebFlux 构建的 API 网关,它为微服务架构提供了一种简单而有效的方式来路由和过滤请求。在微服务环境中,网关作为系统的统一入口,负责请求路由、负载均衡、安全认证、限流等功能。

Spring Cloud Gateway 的配置是通过 `RouteDefinitionLocator` 实例的集合来驱动的,这是理解网关配置的核心概念。

路由定义定位器(RouteDefinitionLocator)

核心接口

RouteDefinitionLocator 是 Spring Cloud Gateway 配置的核心接口,它负责提供路由定义信息。

kotlin
import reactor.core.publisher.Flux

/**
 * 路由定义定位器接口
 * 负责提供路由定义的响应式流
 */
interface RouteDefinitionLocator {
    /**
     * 获取所有路由定义
     * @return 路由定义的响应式流
     */
    fun getRouteDefinitions(): Flux<RouteDefinition>
}
java
public interface RouteDefinitionLocator {
	Flux<RouteDefinition> getRouteDefinitions();
}

默认实现

默认情况下,Spring Cloud Gateway 使用 PropertiesRouteDefinitionLocator 来加载配置属性,它利用 Spring Boot 的 @ConfigurationProperties 机制。

kotlin
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.cloud.gateway.route.RouteDefinition
import reactor.core.publisher.Flux

/**
 * 基于属性文件的路由定义定位器
 * 通过 Spring Boot 的配置属性机制加载路由配置
 */
@ConfigurationProperties("spring.cloud.gateway")
class PropertiesRouteDefinitionLocator : RouteDefinitionLocator {

    private val routes = mutableListOf<RouteDefinition>()

    override fun getRouteDefinitions(): Flux<RouteDefinition> {
        return Flux.fromIterable(routes)
    }

    // getter 和 setter 方法
    fun getRoutes(): List<RouteDefinition> = routes
    fun setRoutes(routes: List<RouteDefinition>) {
        this.routes.clear()
        this.routes.addAll(routes)
    }
}

配置方式

YAML 配置

Spring Cloud Gateway 支持两种配置语法:完整语法和简化语法。以下是两种等价的配置示例:

yaml
spring:
  cloud:
    gateway:
      routes:
        # 完整语法配置
        - id: setstatus_route
          uri: https://example.org
          filters:
            - name: SetStatus
              args:
                status: 401
        # 简化语法配置
        - id: setstatusshortcut_route
          uri: https://example.org
          filters:
            - SetStatus=401

配置结构图解

实际业务场景示例

在电商系统中,我们可能需要配置多个路由来处理不同的业务模块:

kotlin
import org.springframework.cloud.gateway.route.RouteLocator
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

/**
 * 电商系统网关路由配置
 * 解决了多个微服务的统一入口和路由分发问题
 */
@Configuration
class EcommerceGatewayConfig {

    /**
     * 通过编程方式配置路由
     * 适用于需要动态路由或复杂路由逻辑的场景
     */
    @Bean
    fun customRouteLocator(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            // 用户服务路由
            .route("user-service") { r ->
                r.path("/api/users/**")
                    .filters { f ->
                        f.stripPrefix(1) // 移除 /api 前缀
                         .addRequestHeader("X-Service", "user-service")
                    }
                    .uri("lb://user-service") // 负载均衡到用户服务
            }
            // 商品服务路由
            .route("product-service") { r ->
                r.path("/api/products/**")
                    .and()
                    .method("GET", "POST") // 只允许 GET 和 POST 请求
                    .filters { f ->
                        f.stripPrefix(1)
                         .circuitBreaker { config ->
                             config.name = "product-circuit-breaker"
                             config.fallbackUri = "forward:/fallback/products"
                         }
                    }
                    .uri("lb://product-service")
            }
            // 订单服务路由(需要认证)
            .route("order-service") { r ->
                r.path("/api/orders/**")
                    .filters { f ->
                        f.stripPrefix(1)
                         .requestRateLimiter { config ->
                             config.rateLimiter = redisRateLimiter()
                             config.keyResolver = userKeyResolver()
                         }
                    }
                    .uri("lb://order-service")
            }
            .build()
    }

    /**
     * Redis 限流器配置
     * 用于控制用户请求频率
     */
    @Bean
    fun redisRateLimiter(): RedisRateLimiter {
        return RedisRateLimiter(10, 20) // 每秒10个请求,突发20个
    }

    /**
     * 用户键解析器
     * 根据用户ID进行限流
     */
    @Bean
    fun userKeyResolver(): KeyResolver {
        return KeyResolver { exchange ->
            exchange.request.headers.getFirst("X-User-Id")?.let {
                Mono.just(it)
            } ?: Mono.just("anonymous")
        }
    }
}

在生产环境中,建议使用编程方式配置复杂路由,而简单路由可以使用 YAML 配置,这样既保持了灵活性又提高了可维护性。

动态配置源

数据库配置

对于生产环境,从外部数据源加载配置通常更加灵活。Spring Cloud Gateway 的未来版本将支持基于 Spring Data Repository 的实现:

kotlin
import org.springframework.data.repository.reactive.ReactiveCrudRepository
import org.springframework.stereotype.Repository
import reactor.core.publisher.Flux

/**
 * 路由定义数据访问接口
 * 支持从数据库动态加载路由配置
 */
@Repository
interface RouteDefinitionRepository : ReactiveCrudRepository<RouteDefinitionEntity, String> {

    /**
     * 查找启用的路由定义
     * @return 启用的路由定义流
     */
    fun findByEnabledTrue(): Flux<RouteDefinitionEntity>

    /**
     * 根据服务名查找路由
     * @param serviceName 服务名称
     * @return 匹配的路由定义流
     */
    fun findByServiceName(serviceName: String): Flux<RouteDefinitionEntity>
}

/**
 * 基于数据库的路由定义定位器
 * 解决了路由配置的动态管理问题
 */
@Component
class DatabaseRouteDefinitionLocator(
    private val routeRepository: RouteDefinitionRepository
) : RouteDefinitionLocator {

    override fun getRouteDefinitions(): Flux<RouteDefinition> {
        return routeRepository.findByEnabledTrue()
            .map { entity -> convertToRouteDefinition(entity) }
            .doOnError { error ->
                log.error("Failed to load route definitions from database", error)
            }
    }

    /**
     * 将数据库实体转换为路由定义
     */
    private fun convertToRouteDefinition(entity: RouteDefinitionEntity): RouteDefinition {
        val routeDefinition = RouteDefinition()
        routeDefinition.id = entity.id
        routeDefinition.uri = URI.create(entity.uri)

        // 解析断言配置
        entity.predicates?.let { predicatesJson ->
            routeDefinition.predicates = parsePredicates(predicatesJson)
        }

        // 解析过滤器配置
        entity.filters?.let { filtersJson ->
            routeDefinition.filters = parseFilters(filtersJson)
        }

        return routeDefinition
    }
}

Redis 配置

kotlin
import org.springframework.data.redis.core.ReactiveRedisTemplate
import org.springframework.stereotype.Component
import com.fasterxml.jackson.databind.ObjectMapper

/**
 * 基于 Redis 的路由定义定位器
 * 支持分布式环境下的路由配置共享
 */
@Component
class RedisRouteDefinitionLocator(
    private val redisTemplate: ReactiveRedisTemplate<String, String>,
    private val objectMapper: ObjectMapper
) : RouteDefinitionLocator {

    companion object {
        private const val ROUTES_KEY = "gateway:routes"
    }

    override fun getRouteDefinitions(): Flux<RouteDefinition> {
        return redisTemplate.opsForHash<String, String>()
            .values(ROUTES_KEY)
            .map { json -> objectMapper.readValue(json, RouteDefinition::class.java) }
            .doOnError { error ->
                log.error("Failed to load route definitions from Redis", error)
            }
    }

    /**
     * 添加或更新路由定义
     * @param routeDefinition 路由定义
     */
    fun saveRouteDefinition(routeDefinition: RouteDefinition): Mono<Boolean> {
        val json = objectMapper.writeValueAsString(routeDefinition)
        return redisTemplate.opsForHash<String, String>()
            .put(ROUTES_KEY, routeDefinition.id, json)
    }

    /**
     * 删除路由定义
     * @param routeId 路由ID
     */
    fun deleteRouteDefinition(routeId: String): Mono<Long> {
        return redisTemplate.opsForHash<String, String>()
            .remove(ROUTES_KEY, routeId)
    }
}

路由定义监控

启用监控指标

要启用 RouteDefinition 监控指标,需要添加 Spring Boot Actuator 依赖:

kotlin
// build.gradle.kts
dependencies {
    implementation("org.springframework.boot:spring-boot-starter-actuator")
    implementation("org.springframework.cloud:spring-cloud-starter-gateway")
}

配置监控

yaml
spring:
  cloud:
    gateway:
      # 启用网关监控指标
      metrics:
        enabled: true
      routes:
        # 路由配置...

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,gateway
  endpoint:
    gateway:
      enabled: true
    metrics:
      enabled: true

监控指标说明

启用监控后,将提供以下指标:

指标名称描述访问路径
spring.cloud.gateway.routes.count当前路由定义数量/actuator/metrics/spring.cloud.gateway.routes.count
gateway.requests网关请求计数/actuator/metrics/gateway.requests
gateway.request.duration请求处理时间/actuator/metrics/gateway.request.duration

自定义监控指标

kotlin
import io.micrometer.core.instrument.MeterRegistry
import io.micrometer.core.instrument.Timer
import org.springframework.stereotype.Component

/**
 * 网关监控指标收集器
 * 提供自定义的业务监控指标
 */
@Component
class GatewayMetricsCollector(
    private val meterRegistry: MeterRegistry
) {

    private val routeTimer = Timer.builder("gateway.route.duration")
        .description("Route processing time")
        .register(meterRegistry)

    private val errorCounter = meterRegistry.counter("gateway.route.errors")

    /**
     * 记录路由处理时间
     */
    fun recordRouteTime(routeId: String, duration: Long) {
        Timer.Sample.start(meterRegistry)
            .stop(Timer.builder("gateway.route.duration")
                .tag("route", routeId)
                .register(meterRegistry))
    }

    /**
     * 记录路由错误
     */
    fun recordRouteError(routeId: String, errorType: String) {
        meterRegistry.counter("gateway.route.errors",
            "route", routeId,
            "error", errorType)
            .increment()
    }
}

配置最佳实践

1. 环境隔离配置

yaml
# application.yml
spring:
  profiles:
    active: ${SPRING_PROFILES_ACTIVE:dev}

---
# 开发环境配置
spring:
  config:
    activate:
      on-profile: dev
  cloud:
    gateway:
      routes:
        - id: user-service-dev
          uri: http://localhost:8081
          predicates:
            - Path=/api/users/**

---
# 生产环境配置
spring:
  config:
    activate:
      on-profile: prod
  cloud:
    gateway:
      routes:
        - id: user-service-prod
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
          filters:
            - name: CircuitBreaker
              args:
                name: user-service-cb
                fallbackUri: forward:/fallback/users

2. 配置加密

kotlin
import org.springframework.cloud.context.config.annotation.RefreshScope
import org.springframework.boot.context.properties.ConfigurationProperties

/**
 * 网关安全配置
 * 支持配置刷新和敏感信息加密
 */
@RefreshScope
@ConfigurationProperties(prefix = "gateway.security")
data class GatewaySecurityProperties(
    var jwtSecret: String = "",
    var apiKeys: Map<String, String> = emptyMap(),
    var corsAllowedOrigins: List<String> = emptyList()
)

在生产环境中,敏感配置信息(如 JWT 密钥、API 密钥)应该使用配置加密或外部密钥管理服务。

3. 配置验证

kotlin
import org.springframework.boot.context.event.ApplicationReadyEvent
import org.springframework.context.event.EventListener
import org.springframework.stereotype.Component

/**
 * 网关配置验证器
 * 在应用启动时验证路由配置的正确性
 */
@Component
class GatewayConfigValidator(
    private val routeDefinitionLocator: RouteDefinitionLocator
) {

    @EventListener(ApplicationReadyEvent::class)
    fun validateRouteConfigurations() {
        routeDefinitionLocator.getRouteDefinitions()
            .doOnNext { route ->
                validateRoute(route)
            }
            .subscribe(
                { log.info("Route validation completed successfully") },
                { error -> log.error("Route validation failed", error) }
            )
    }

    private fun validateRoute(route: RouteDefinition) {
        // 验证路由ID唯一性
        require(route.id.isNotBlank()) { "Route ID cannot be blank" }

        // 验证URI格式
        require(route.uri != null) { "Route URI cannot be null for route: ${route.id}" }

        // 验证断言配置
        require(route.predicates.isNotEmpty()) { "Route must have at least one predicate: ${route.id}" }

        log.info("Route ${route.id} validation passed")
    }
}

总结

Spring Cloud Gateway 的配置系统具有以下特点:

  1. 灵活性:支持多种配置源(属性文件、数据库、Redis 等)
  2. 可扩展性:通过 RouteDefinitionLocator 接口可以自定义配置加载逻辑
  3. 监控能力:内置监控指标,便于运维管理
  4. 动态性:支持运行时配置更新和路由刷新

选择合适的配置方式取决于具体的业务场景:

  • 简单场景使用 YAML 配置
  • 需要动态管理时使用数据库配置
  • 分布式环境推荐使用 Redis 配置
  • 复杂路由逻辑建议使用编程方式配置

通过合理的配置策略,Spring Cloud Gateway 可以很好地解决微服务架构中的 API 网关需求,提供统一的服务入口和强大的路由管理能力。