Skip to content

SetRequestHeader GatewayFilter Factory

概述

SetRequestHeader 是 Spring Cloud Gateway 中的一个重要过滤器工厂,用于设置请求头信息。它能够在请求转发到下游服务之前,动态地添加或替换 HTTP 请求头,这在微服务架构中非常有用,特别是在需要传递认证信息、跟踪信息或其他元数据时。

IMPORTANT

SetRequestHeader 过滤器会替换(而不是添加)具有给定名称的所有请求头。如果需要添加多个同名请求头,请考虑使用其他方式。

核心功能

解决的问题

在微服务架构中,经常需要:

  • 为下游服务添加认证令牌
  • 传递用户身份信息
  • 添加请求跟踪 ID
  • 设置特定的服务标识
  • 传递业务上下文信息

工作原理

基本配置

参数说明

SetRequestHeader 过滤器接受两个参数:

  • name:请求头的名称
  • value:请求头的值

基础配置示例

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: setrequestheader_route
          uri: https://example.org
          filters:
            - SetRequestHeader=X-Request-Red, Blue
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 GatewayConfig {

    @Bean
    fun customRouteLocator(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            .route("setrequestheader_route") { r ->
                r.path("/api/**")
                    .filters { f ->
                        f.setRequestHeader("X-Request-Red", "Blue")
                    }
                    .uri("https://example.org")
            }
            .build()
    }
}

实际业务场景

场景 1:添加认证令牌

在微服务架构中,Gateway 通常负责统一认证,然后将认证信息传递给下游服务:

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: user_service_route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - SetRequestHeader=Authorization, Bearer ${jwt.token}
            - SetRequestHeader=X-User-Id, ${user.id}
kotlin
import org.springframework.cloud.gateway.filter.GatewayFilter
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory
import org.springframework.stereotype.Component

@Component
class AuthenticationHeaderFilter : AbstractGatewayFilterFactory<AuthenticationHeaderFilter.Config>() {

    override fun apply(config: Config): GatewayFilter {
        return GatewayFilter { exchange, chain ->
            val request = exchange.request.mutate()
                // 从JWT中提取用户信息
                .header("X-User-Id", extractUserId(exchange))
                .header("X-User-Role", extractUserRole(exchange))
                .header("X-Request-Time", System.currentTimeMillis().toString())
                .build()

            chain.filter(exchange.mutate().request(request).build())
        }
    }

    private fun extractUserId(exchange: ServerWebExchange): String {
        // 实际业务中从JWT或Session中提取用户ID
        return "user123"
    }

    private fun extractUserRole(exchange: ServerWebExchange): String {
        // 提取用户角色
        return "ADMIN"
    }

    class Config {
        // 配置参数
    }
}

场景 2:请求链路追踪

为每个请求添加唯一的追踪 ID,方便日志分析和问题排查:

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: order_service_route
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
          filters:
            - SetRequestHeader=X-Trace-Id, ${T(java.util.UUID).randomUUID().toString()}
            - SetRequestHeader=X-Service-Name, order-service

在生产环境中,建议使用专门的链路追踪工具如 Spring Cloud Sleuth 或 Zipkin,而不是手动设置追踪 ID。

URI 变量支持

SetRequestHeader 过滤器支持 URI 变量,可以动态地根据请求路径或主机信息设置请求头值。

基于路径变量

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: dynamic_header_route
          uri: https://example.org
          predicates:
            - Path=/api/{version}/users/**
          filters:
            - SetRequestHeader=X-API-Version, {version}

基于主机变量

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: tenant_based_route
          uri: https://example.org
          predicates:
            - Host={tenant}.myhost.org
          filters:
            - SetRequestHeader=X-Tenant-Id, {tenant}
            - SetRequestHeader=foo, bar-{tenant}

复杂变量示例

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: complex_variable_route
          uri: lb://backend-service
          predicates:
            - Host={tenant}.api.{env}.example.com
            - Path=/api/{version}/{service}/**
          filters:
            - SetRequestHeader=X-Tenant, {tenant}
            - SetRequestHeader=X-Environment, {env}
            - SetRequestHeader=X-API-Version, {version}
            - SetRequestHeader=X-Service-Name, {service}
kotlin
@Configuration
class DynamicHeaderConfig {

    @Bean
    fun dynamicRouteLocator(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            .route("dynamic_header_route") { r ->
                r.host("{tenant}.api.example.com")
                    .and()
                    .path("/api/{version}/users/**")
                    .filters { f ->
                        f.setRequestHeader("X-Tenant", "{tenant}")
                         .setRequestHeader("X-API-Version", "{version}")
                         .setRequestHeader("X-Request-Source", "gateway")
                    }
                    .uri("lb://user-service")
            }
            .build()
    }
}

高级用法

条件性设置请求头

结合谓词条件,可以根据不同的条件设置不同的请求头:

yaml
spring:
  cloud:
    gateway:
      routes:
        # 移动端请求
        - id: mobile_route
          uri: lb://mobile-service
          predicates:
            - Header=User-Agent, .*Mobile.*
          filters:
            - SetRequestHeader=X-Client-Type, mobile
            - SetRequestHeader=X-Feature-Flag, mobile-optimized

        # 桌面端请求
        - id: desktop_route
          uri: lb://web-service
          predicates:
            - Header=User-Agent, .*(?!Mobile).*
          filters:
            - SetRequestHeader=X-Client-Type, desktop
            - SetRequestHeader=X-Feature-Flag, full-features

与其他过滤器组合使用

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: comprehensive_route
          uri: lb://backend-service
          predicates:
            - Path=/api/**
          filters:
            # 限流
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
            # 设置请求头
            - SetRequestHeader=X-RateLimit-Applied, true
            - SetRequestHeader=X-Gateway-Version, v2.0
            # 重试机制
            - name: Retry
              args:
                retries: 3
                statuses: BAD_GATEWAY,GATEWAY_TIMEOUT

注意事项和最佳实践

重要提醒

WARNING

SetRequestHeader 会替换(而不是添加)所有具有给定名称的请求头。如果下游服务返回了 X-Request-Red:1234,它将被替换为 X-Request-Red:Blue

最佳实践

TIP

  1. 命名规范:使用有意义的请求头名称,建议使用 X- 前缀表示自定义请求头
  2. 避免覆盖:避免覆盖标准 HTTP 请求头,如 Content-TypeAuthorization
  3. 性能考虑:避免设置过多的请求头,每个请求头都会增加网络传输开销
  4. 安全性:不要在请求头中传递敏感信息,如密码或完整的认证令牌

常见错误

DANGER

避免以下常见错误:

  1. 覆盖关键的 HTTP 标准请求头
  2. 在请求头中传递敏感信息
  3. 设置过长的请求头值
  4. 忘记处理特殊字符和编码问题

调试和监控

启用日志

yaml
logging:
  level:
    org.springframework.cloud.gateway: DEBUG
    org.springframework.cloud.gateway.filter: TRACE

自定义日志过滤器

kotlin
@Component
class RequestHeaderLoggingFilter : GlobalFilter, Ordered {

    private val logger = LoggerFactory.getLogger(RequestHeaderLoggingFilter::class.java)

    override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
        val request = exchange.request

        // 记录所有请求头
        logger.info("Request headers for ${request.path}: ${request.headers}")

        return chain.filter(exchange)
    }

    override fun getOrder(): Int = -1 // 确保在其他过滤器之前执行
}

总结

SetRequestHeader 过滤器是 Spring Cloud Gateway 中一个简单但强大的工具,它能够:

  • ✅ 动态设置请求头信息
  • ✅ 支持 URI 变量替换
  • ✅ 与其他过滤器良好配合
  • ✅ 满足微服务间通信需求

通过合理使用 SetRequestHeader 过滤器,可以有效地实现服务间的信息传递、认证授权、链路追踪等功能,是构建健壮微服务架构的重要组件。

在实际项目中,建议结合业务需求和安全考虑,制定统一的请求头命名和使用规范,确保系统的可维护性和安全性。