Skip to content

RewriteRequestParameter GatewayFilter Factory

概述

RewriteRequestParameter 是 Spring Cloud Gateway 中的一个过滤器工厂,用于重写请求参数的值。这个过滤器在实际业务场景中非常有用,比如需要对传入的请求参数进行标准化、版本控制或者安全处理时。

核心功能

RewriteRequestParameter 过滤器工厂接收两个核心参数:

  • name:要重写的请求参数名称
  • replacement:替换后的新值

工作原理

业务场景与应用

1. 营销活动参数标准化

在电商系统中,不同的营销渠道可能使用不同的活动标识,通过 Gateway 统一标准化这些参数。

这种方式可以避免在每个微服务中都实现参数转换逻辑,降低了系统的复杂性。

2. API 版本控制

当需要将旧版本的 API 参数映射到新版本时,可以使用此过滤器进行平滑迁移。

3. 安全参数过滤

将敏感或不规范的参数值替换为安全的默认值。

配置详解

基础配置

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: rewriterequestparameter_route
          uri: https://example.org
          predicates:
            - Path=/products # 匹配路径
          filters:
            - RewriteRequestParameter=campaign,fall2023 # 参数名,新值
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 {

    /**
     * 配置路由和过滤器
     * 重写请求参数campaign的值为fall2023
     */
    @Bean
    fun customRouteLocator(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            .route("rewriterequestparameter_route") { r ->
                r.path("/products")  // 路径匹配
                    .filters { f ->
                        f.rewriteRequestParameter("campaign", "fall2023")  // 重写参数
                    }
                    .uri("https://example.org")  // 目标服务
            }
            .build()
    }
}

高级配置示例

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 AdvancedGatewayConfig {

    /**
     * 复杂的参数重写场景
     * 处理多个不同的参数重写需求
     */
    @Bean
    fun advancedRouteLocator(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            // 营销活动参数标准化
            .route("marketing_route") { r ->
                r.path("/api/marketing/**")
                    .filters { f ->
                        f.rewriteRequestParameter("source", "official")  // 统一来源标识
                         .rewriteRequestParameter("version", "v2")        // 统一版本参数
                    }
                    .uri("http://marketing-service")
            }
            // 用户API参数规范化
            .route("user_route") { r ->
                r.path("/api/users/**")
                    .filters { f ->
                        f.rewriteRequestParameter("format", "json")      // 统一响应格式
                         .rewriteRequestParameter("locale", "zh-CN")     // 统一语言设置
                    }
                    .uri("http://user-service")
            }
            .build()
    }
}

重要特性说明

参数处理规则

IMPORTANT

  • 如果存在多个同名参数,它们将被替换为单个值
  • 如果请求中不存在指定的参数,不会进行任何更改
  • 参数值替换是完全替换,而非部分替换

实际效果演示

text
# 原始请求
GET /products?campaign=old&category=electronics&campaign=summer

# 经过 RewriteRequestParameter=campaign,fall2023 处理后
GET /products?campaign=fall2023&category=electronics

# 注意:多个同名参数被合并为单个参数

与其他过滤器的组合使用

kotlin
@Configuration
class CombinedFiltersConfig {

    /**
     * 组合使用多个过滤器
     * 演示参数重写与其他过滤器的协同工作
     */
    @Bean
    fun combinedRouteLocator(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            .route("combined_filters_route") { r ->
                r.path("/api/products/**")
                    .filters { f ->
                        f.addRequestHeader("X-Gateway-Filter", "Applied")     // 添加请求头
                         .rewriteRequestParameter("version", "v3")            // 重写参数
                         .addRequestParameter("source", "gateway")            // 添加新参数
                         .rewritePath("/api/products/(?<segment>.*)", "/v3/products/\${segment}")  // 重写路径
                    }
                    .uri("http://product-service")
            }
            .build()
    }
}

最佳实践

1. 参数验证与默认值设置

kotlin
@Component
class RequestParameterValidator : GlobalFilter, Ordered {

    /**
     * 在参数重写之前进行验证
     * 确保参数的有效性
     */
    override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
        val request = exchange.request
        val queryParams = request.queryParams

        // 验证关键参数是否存在
        if (request.path.value().startsWith("/api/products")) {
            val campaign = queryParams.getFirst("campaign")

            // 如果campaign参数为空或无效,记录日志
            if (campaign.isNullOrBlank()) {
                println("请求缺少campaign参数,将通过过滤器设置默认值")
            }
        }

        return chain.filter(exchange)
    }

    override fun getOrder(): Int = -1  // 在RewriteRequestParameter之前执行
}

2. 条件性参数重写

kotlin
import org.springframework.cloud.gateway.filter.GatewayFilter
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory
import org.springframework.stereotype.Component

/**
 * 自定义条件性参数重写过滤器
 * 只在满足特定条件时才重写参数
 */
@Component
class ConditionalRewriteRequestParameterGatewayFilterFactory :
    AbstractGatewayFilterFactory<ConditionalRewriteRequestParameterGatewayFilterFactory.Config>() {

    data class Config(
        var paramName: String = "",      // 要重写的参数名
        var newValue: String = "",       // 新值
        var condition: String = ""       // 重写条件
    )

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

            // 检查条件是否满足
            val shouldRewrite = when (config.condition) {
                "missing" -> !queryParams.containsKey(config.paramName)
                "empty" -> queryParams[config.paramName].isNullOrBlank()
                "always" -> true
                else -> false
            }

            if (shouldRewrite) {
                queryParams[config.paramName] = config.newValue

                // 重建请求
                val newRequest = request.mutate()
                    .uri(request.uri.resolve("?${buildQueryString(queryParams)}"))
                    .build()

                chain.filter(exchange.mutate().request(newRequest).build())
            } else {
                chain.filter(exchange)
            }
        }
    }

    /**
     * 构建查询字符串
     */
    private fun buildQueryString(params: Map<String, String>): String {
        return params.entries.joinToString("&") { "${it.key}=${it.value}" }
    }
}

监控与调试

启用调试日志

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

自定义监控过滤器

kotlin
import org.springframework.cloud.gateway.filter.GlobalFilter
import org.springframework.core.Ordered
import org.springframework.stereotype.Component
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono

@Component
class ParameterRewriteMonitorFilter : GlobalFilter, Ordered {

    /**
     * 监控参数重写的效果
     * 记录重写前后的参数变化
     */
    override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
        val originalParams = exchange.request.queryParams

        return chain.filter(exchange).doFinally {
            val finalParams = exchange.request.queryParams

            // 比较参数变化
            if (originalParams != finalParams) {
                println("参数重写监控:")
                println("原始参数: $originalParams")
                println("最终参数: $finalParams")
            }
        }
    }

    override fun getOrder(): Int = Ordered.LOWEST_PRECEDENCE
}

常见问题与解决方案

1. 中文参数编码问题

当处理包含中文的参数时,需要注意 URL 编码问题。

kotlin
import java.net.URLEncoder
import java.net.URLDecoder
import java.nio.charset.StandardCharsets

/**
 * 处理中文参数的重写
 */
fun handleChineseParameters(paramValue: String): String {
    return try {
        // 先解码,再重新编码
        val decoded = URLDecoder.decode(paramValue, StandardCharsets.UTF_8)
        URLEncoder.encode(decoded, StandardCharsets.UTF_8)
    } catch (e: Exception) {
        paramValue // 如果编码失败,返回原值
    }
}

2. 性能优化

对于高并发场景,建议缓存重写规则,避免重复计算。

kotlin
import org.springframework.cache.annotation.Cacheable
import org.springframework.stereotype.Service

@Service
class ParameterRewriteService {

    /**
     * 缓存参数重写规则
     * 提高高并发场景下的性能
     */
    @Cacheable("parameterRewrites")
    fun getRewriteRule(paramName: String, originalValue: String): String? {
        // 复杂的重写逻辑
        return when (paramName) {
            "campaign" -> mapCampaignValue(originalValue)
            "version" -> mapVersionValue(originalValue)
            else -> null
        }
    }

    private fun mapCampaignValue(value: String): String {
        return when (value.lowercase()) {
            "old", "legacy" -> "fall2023"
            "new", "current" -> "winter2024"
            else -> value
        }
    }

    private fun mapVersionValue(value: String): String {
        return when (value) {
            "1", "v1" -> "v2"
            "2", "v2" -> "v3"
            else -> value
        }
    }
}

总结

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

  • 参数标准化:统一不同来源的参数格式
  • 版本迁移:平滑处理 API 版本升级
  • 安全防护:过滤和替换不安全的参数值
  • 业务规则:实现复杂的业务参数转换逻辑

通过合理配置和使用这个过滤器,可以大大简化微服务架构中的参数处理逻辑,提高系统的可维护性和安全性。

在使用此过滤器时,要特别注意参数的唯一性处理和性能影响,建议在生产环境中进行充分的测试和监控。