Skip to content

MapRequestHeader GatewayFilter 工厂

概述

MapRequestHeader 用于在请求头之间进行映射操作。它可以从现有的请求头中提取值,并创建一个新的请求头。这个过滤器在需要对请求头进行转换或标准化的场景中非常有用。

功能特性

MapRequestHeader 过滤器工厂接受两个参数:

  • fromHeader:源请求头的名称
  • toHeader:目标请求头的名称

工作原理

核心特性

MapRequestHeader 过滤器的核心特性:

  • 从现有的请求头中提取值并创建新的请求头
  • 如果源请求头不存在,过滤器不会产生任何影响
  • 如果目标请求头已存在,新值会追加到现有值中

配置示例

YAML 配置

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: map_request_header_route
          uri: https://example.org
          filters:
            - MapRequestHeader=Blue, X-Request-Red
kotlin
@Configuration
class GatewayConfig {

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

实际业务场景

场景 1:API 版本标准化

在微服务架构中,不同的客户端可能使用不同的版本标识方式。我们可以使用 MapRequestHeader 将它们标准化:

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: version_standardization
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
          filters:
            # 将客户端的 API-Version 头部映射为服务端期望的 X-API-Version
            - MapRequestHeader=API-Version, X-API-Version
kotlin
@Component
class VersionMappingGatewayFilterFactory : AbstractGatewayFilterFactory<VersionMappingGatewayFilterFactory.Config>() {

    data class Config(
        var fromHeader: String = "",
        var toHeader: String = ""
    )

    override fun apply(config: Config): GatewayFilter {
        return GatewayFilter { exchange, chain ->
            // 获取原始请求
            val request = exchange.request

            // 检查源头部是否存在
            val fromHeaderValue = request.headers.getFirst(config.fromHeader)

            if (fromHeaderValue != null) {
                // 创建新的请求,添加目标头部
                val modifiedRequest = request.mutate()
                    .header(config.toHeader, fromHeaderValue)
                    .build()

                // 使用修改后的请求继续处理
                chain.filter(exchange.mutate().request(modifiedRequest).build())
            } else {
                // 如果源头部不存在,直接继续处理
                chain.filter(exchange)
            }
        }
    }

    override fun getConfigClass(): Class<Config> = Config::class.java
}

场景 2:用户身份信息传递

在需要将用户身份信息传递给下游服务的场景中:

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: user_identity_mapping
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
          filters:
            # 将认证头部中的用户ID映射为下游服务期望的格式
            - MapRequestHeader=X-User-ID, X-Current-User
            # 将客户端类型映射为内部标识
            - MapRequestHeader=Client-Type, X-Client-Source

场景 3:调试和监控

在开发和调试阶段,可以使用 MapRequestHeader 来添加追踪信息:

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: debug_tracing
          uri: lb://payment-service
          predicates:
            - Path=/api/payments/**
          filters:
            # 将请求ID映射为追踪头部
            - MapRequestHeader=Request-ID, X-Trace-ID
            # 将会话ID映射为关联头部
            - MapRequestHeader=Session-ID, X-Correlation-ID

高级用法

结合其他过滤器使用

MapRequestHeader 通常与其他过滤器组合使用,形成完整的请求处理流水线:

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: comprehensive_processing
          uri: lb://business-service
          predicates:
            - Path=/api/business/**
          filters:
            # 1. 添加请求头
            - AddRequestHeader=X-Gateway-Source, API-Gateway
            # 2. 映射版本信息
            - MapRequestHeader=API-Version, X-Service-Version
            # 3. 映射用户信息
            - MapRequestHeader=Authorization, X-Auth-Token
            # 4. 限流
            - RequestRateLimiter=redis-rate-limiter
kotlin
@Configuration
class ComprehensiveFilterConfig {

    @Bean
    fun businessRoutes(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            .route("comprehensive_business_route") { r ->
                r.path("/api/business/**")
                    .filters { f ->
                        f.addRequestHeader("X-Gateway-Source", "API-Gateway")
                         .mapRequestHeader("API-Version", "X-Service-Version")
                         .mapRequestHeader("Authorization", "X-Auth-Token")
                         .requestRateLimiter { rl ->
                             rl.setRateLimiter(redisRateLimiter())
                         }
                    }
                    .uri("lb://business-service")
            }
            .build()
    }

    @Bean
    fun redisRateLimiter(): RedisRateLimiter {
        return RedisRateLimiter(10, 20) // 10个令牌/秒,突发20个
    }
}

注意事项和最佳实践

使用 MapRequestHeader 时需要注意以下几点:

1. 头部名称规范

kotlin
// ✅ 推荐:使用标准的头部命名规范
- MapRequestHeader=X-Client-Version, X-API-Version

// ❌ 避免:使用非标准或冲突的头部名称
- MapRequestHeader=clientversion, version 

2. 值的累积行为

如果目标头部已经存在,新值会被追加而不是替换:

yaml
# 假设原始请求包含:X-Custom-Header: value1
# 配置:MapRequestHeader=Source-Header, X-Custom-Header
# 结果:X-Custom-Header: value1, value2 (如果 Source-Header 的值是 value2)

3. 性能考虑

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

    data class Config(
        var mappings: Map<String, String> = emptyMap()
    )

    override fun apply(config: Config): GatewayFilter {
        return GatewayFilter { exchange, chain ->
            val request = exchange.request
            val builder = request.mutate()

            // 批量处理多个头部映射,提高性能
            config.mappings.forEach { (fromHeader, toHeader) ->
                request.headers.getFirst(fromHeader)?.let { value ->
                    builder.header(toHeader, value)
                }
            }

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

    override fun getConfigClass(): Class<Config> = Config::class.java
}

故障排查

常见问题

Details

故障排查指南

问题 1:映射的头部没有出现在下游请求中

kotlin
// 调试用的日志过滤器
@Component
class HeaderDebugFilter : GlobalFilter, Ordered {

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

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

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

        return chain.filter(exchange)
    }

    override fun getOrder(): Int = -1 // 最高优先级
}

问题 2:头部值格式不正确

yaml
# 检查源头部是否存在和格式是否正确
spring:
  cloud:
    gateway:
      routes:
        - id: debug_route
          uri: lb://test-service
          filters:
            - MapRequestHeader=Source-Header, Target-Header
            # 添加日志过滤器查看头部信息
            - name: RequestSize
              args:
                maxSize: 5000000

总结

MapRequestHeader 过滤器工厂是 Spring Cloud Gateway 中一个简单但强大的工具,它解决了以下核心问题:

  1. 请求头标准化:统一不同客户端的头部格式
  2. 信息传递:将认证、版本等信息传递给下游服务
  3. 兼容性:支持遗留系统和新系统之间的头部映射
  4. 调试支持:为请求添加追踪和调试信息

通过合理使用 MapRequestHeader,可以大大简化微服务架构中的请求头管理,提高系统的可维护性和可扩展性。

MapRequestHeader 是一个无状态的过滤器,不会影响网关的性能,可以安全地在生产环境中使用。