Skip to content

RewritePath GatewayFilter Factory

概述

RewritePath 是 Spring Cloud Gateway 中一个强大的过滤器工厂,它能够在请求转发到下游服务之前动态地重写请求路径。这个过滤器使用 Java 正则表达式提供了灵活的路径重写功能,是微服务架构中实现路径映射和 API 版本控制的重要工具。

RewritePath 过滤器主要解决了微服务网关中路径转换的问题,让外部 API 路径与内部服务路径可以完全解耦。

工作原理

RewritePath 过滤器接受两个参数:

  • regexp:用于匹配原始请求路径的正则表达式
  • replacement:用于替换匹配部分的新路径模式

配置方式

YAML 配置

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: rewritepath_route
          uri: https://example.org
          predicates:
            - Path=/red/**
          filters:
            - RewritePath=/red/?(?<segment>.*), /${segment}
kotlin
@Configuration
class GatewayConfig {

    @Bean
    fun customRouteLocator(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            .route("rewritepath_route") { r ->
                r.path("/red/**")
                    .filters { f ->
                        f.rewritePath("/red/?(?<segment>.*)", "/\${segment}")
                    }
                    .uri("https://example.org")
            }
            .build()
    }
}

在 YAML 配置中,`$` 符号需要转义为 `$\`,这是由于 YAML 规范的要求。

实际业务场景

场景一:API 版本控制

在实际项目中,我们经常需要对外提供统一的 API 接口,但内部服务可能有不同的路径结构:

yaml
spring:
  cloud:
    gateway:
      routes:
        # 用户服务 - 移除版本前缀
        - id: user_service_v1
          uri: lb://user-service
          predicates:
            - Path=/api/v1/users/**
          filters:
            - RewritePath=/api/v1/users/(?<segment>.*), /users/${segment}

        # 订单服务 - 路径转换
        - id: order_service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
          filters:
            - RewritePath=/api/orders/(?<segment>.*), /order-management/${segment}

场景二:多租户系统路径重写

kotlin
@Configuration
class MultiTenantGatewayConfig {

    @Bean
    fun multiTenantRoutes(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            // 租户路径重写:/tenant/{tenantId}/api/... -> /api/...
            .route("tenant_route") { r ->
                r.path("/tenant/{tenantId}/api/**")
                    .filters { f ->
                        f.rewritePath(
                            "/tenant/(?<tenantId>[^/]+)/api/(?<segment>.*)",
                            "/api/\${segment}"
                        )
                        // 添加租户ID到请求头
                        .addRequestHeader("X-Tenant-ID", "{tenantId}")
                    }
                    .uri("lb://business-service")
            }
            .build()
    }
}

场景三:遗留系统集成

将旧系统的复杂路径映射到新的 RESTful API 结构:

yaml
spring:
  cloud:
    gateway:
      routes:
        # 遗留系统路径转换
        - id: legacy_system
          uri: http://legacy-service:8080
          predicates:
            - Path=/modern/api/**
          filters:
            - RewritePath=/modern/api/(?<resource>.*), /legacy/servlet/api?resource=${resource}

正则表达式详解

命名捕获组

RewritePath 支持 Java 正则表达式的命名捕获组功能:

yaml
filters:
  # 基本捕获组
  - RewritePath=/api/(?<version>v[0-9]+)/(?<resource>.*), /${resource}

  # 多个命名组
  - RewritePath=/(?<service>[^/]+)/(?<version>v[0-9]+)/(?<path>.*), /${service}-api/${path}

  # 可选匹配
  - RewritePath=/api/(?<version>v[0-9]+)?/?(?<path>.*), /internal/${path}

常用正则模式

Details

常用正则表达式模式

kotlin
// 匹配版本号
val versionPattern = "/api/(?<version>v[0-9]+)/(?<path>.*)"

// 匹配可选的斜杠
val optionalSlashPattern = "/prefix/?(?<segment>.*)"

// 匹配特定资源类型
val resourcePattern = "/api/(?<resource>users|orders|products)/(?<id>[0-9]+)"

// 匹配多级路径
val deepPathPattern = "/(?<service>[^/]+)/(?<module>[^/]+)/(?<action>.*)"

高级用法

结合其他过滤器使用

kotlin
@Bean
fun advancedRoutes(builder: RouteLocatorBuilder): RouteLocator {
    return builder.routes()
        .route("advanced_rewrite") { r ->
            r.path("/api/v1/**")
                .filters { f ->
                    f.rewritePath("/api/v1/(?<segment>.*)", "/v2/\${segment}")
                        .addRequestHeader("X-API-Version", "v2")
                        .addResponseHeader("X-Gateway-Rewrite", "true")
                        .circuitBreaker { config ->
                            config.setName("user-service-cb")
                                .setFallbackUri("forward:/fallback")
                        }
                }
                .uri("lb://user-service")
        }
        .build()
}

条件性路径重写

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

    data class Config(
        var regexp: String = "",
        var replacement: String = "",
        var headerName: String = "",
        var headerValue: String = ""
    )

    override fun apply(config: Config): GatewayFilter {
        return GatewayFilter { exchange, chain ->
            val request = exchange.request
            val headerValue = request.headers.getFirst(config.headerName)

            if (headerValue == config.headerValue) {
                // 满足条件时进行路径重写
                val path = request.uri.rawPath
                val newPath = path.replaceFirst(
                    config.regexp.toRegex(),
                    config.replacement
                )

                val newRequest = request.mutate()
                    .path(newPath)
                    .build()

                chain.filter(exchange.mutate().request(newRequest).build())
            } else {
                // 不满足条件时直接转发
                chain.filter(exchange)
            }
        }
    }
}

测试示例

单元测试

kotlin
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = ["spring.cloud.gateway.routes[0].id=test-route"])
class RewritePathFilterTest {

    @Autowired
    private lateinit var webTestClient: WebTestClient

    @Test
    fun `should rewrite path correctly`() {
        // 模拟请求 /red/users/123
        webTestClient
            .get()
            .uri("/red/users/123")
            .exchange()
            .expectStatus().isOk
            // 验证实际转发的路径是 /users/123
    }

    @Test
    fun `should handle complex path rewriting`() {
        webTestClient
            .get()
            .uri("/api/v1/users/123/orders")
            .exchange()
            .expectStatus().isOk
    }
}

性能优化建议

以下是使用 RewritePath 过滤器时的性能优化建议:

  1. 正则表达式优化

    kotlin
    // 避免过于复杂的正则表达式
    // ❌ 低效
    val complex = "/api/(?:v[0-9]+/)?(?:users/)?(?<id>[0-9]+)/.*"
    
    // ✅ 高效
    val simple = "/api/v[0-9]+/users/(?<id>[0-9]+)"
  2. 缓存编译后的 Pattern

    kotlin
    @Component
    class OptimizedRewriteFilter {
        private val patternCache = ConcurrentHashMap<String, Pattern>()
    
        fun getCompiledPattern(regex: String): Pattern {
            return patternCache.computeIfAbsent(regex) { Pattern.compile(it) }
        }
    }

常见问题与解决方案

问题 1:路径重写不生效

检查以下几个方面:

  1. 路径匹配顺序:确保路由的顺序正确
  2. 正则表达式语法:验证正则表达式是否正确
  3. YAML 转义:确保 $ 符号正确转义为 $\

问题 2:中文路径处理

kotlin
@Configuration
class ChinesePathConfig {

    @Bean
    fun chinesePathRoute(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            .route("chinese_path") { r ->
                r.path("/中文路径/**")
                    .filters { f ->
                        f.rewritePath("/中文路径/(?<segment>.*)", "/api/\${segment}")
                    }
                    .uri("lb://chinese-service")
            }
            .build()
    }
}

问题 3:查询参数处理

kotlin
// RewritePath 只处理路径部分,查询参数会自动保留
// 原始请求: /red/users?page=1&size=10
// 重写后: /users?page=1&size=10

监控与调试

启用调试日志

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

自定义监控

kotlin
@Component
class RewritePathMonitor {

    private val meterRegistry = Metrics.globalRegistry
    private val rewriteCounter = Counter.builder("gateway.rewrite.path")
        .description("Path rewrite operations")
        .register(meterRegistry)

    fun recordRewrite(originalPath: String, newPath: String) {
        rewriteCounter.increment(
            Tags.of(
                "original_path_pattern", extractPattern(originalPath),
                "success", "true"
            )
        )
    }

    private fun extractPattern(path: String): String {
        // 提取路径模式用于监控分类
        return path.split("/").take(3).joinToString("/")
    }
}

总结

RewritePath 过滤器是 Spring Cloud Gateway 中处理路径转换的核心工具,它通过正则表达式提供了强大而灵活的路径重写能力。在微服务架构中,合理使用 RewritePath 可以有效地:

  • 🎯 解耦外部 API 与内部服务路径
  • 🔄 支持 API 版本控制和演化
  • 🏢 简化多租户系统的路径管理
  • 🔗 整合遗留系统和新系统

通过深入理解其工作原理和最佳实践,我们可以构建出更加灵活和可维护的微服务网关系统。

在生产环境中使用时,建议结合监控和日志来跟踪路径重写的效果,确保系统的稳定性和可观测性。