Appearance
流式 Java 路由 API
概述
Spring Cloud Gateway 提供了 RouteLocatorBuilder Bean,它包含一个流式(Fluent)API,允许我们在 Java/Kotlin 中以编程方式简单地配置路由规则。
流式 API 是一种编程模式,通过方法链式调用来构建复杂的对象配置,使代码更加直观和易读。
业务场景
在微服务架构中,网关通常需要处理以下业务场景:
- 图片服务路由:根据不同的图片格式(PNG、WebP)路由到不同的处理服务
- 限流控制:对特定域名的请求进行流量限制
- 响应头添加:为不同的服务添加特定的响应头信息
- 负载均衡:将请求分发到不同的后端服务实例
流式 API 的优势
传统的配置文件方式虽然简单,但在复杂的路由规则下显得力不从心。流式 API 解决了以下问题:
- 动态配置:可以根据运行时条件动态调整路由规则
- 复杂逻辑:支持复杂的谓词组合(AND、OR、NOT)
- 类型安全:编译时检查,减少配置错误
- 代码复用:可以将常用的路由配置封装成方法
基本用法示例
图片服务路由配置
以下示例展示了如何配置一个图片处理服务的路由规则:
kotlin
import org.springframework.cloud.gateway.filter.factory.ThrottleGatewayFilterFactory
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
import java.util.concurrent.TimeUnit
@Configuration
class GatewayConfiguration {
@Bean
fun customRouteLocator(
builder: RouteLocatorBuilder,
throttle: ThrottleGatewayFilterFactory
): RouteLocator {
return builder.routes()
// PNG 图片处理路由:匹配特定域名和路径
.route { r ->
r.host("**.abc.org") // 匹配所有 abc.org 子域名
.and().path("/image/png") // 并且路径为 /image/png
.filters { f ->
// 添加自定义响应头,用于标识处理的服务
f.addResponseHeader("X-TestHeader", "foobar")
}
.uri("http://httpbin.org:80") // 转发到目标服务
}
// WebP 图片处理路由:仅匹配路径
.route { r ->
r.path("/image/webp") // 匹配 WebP 图片请求
.filters { f ->
// 添加另一个自定义响应头
f.addResponseHeader("X-AnotherHeader", "baz")
}
.uri("http://httpbin.org:80") // 转发到同一个服务
.metadata("key", "value") // 添加路由元数据
}
// 限流路由:对特定域名进行流量控制
.route { r ->
r.order(-1) // 设置路由优先级(数字越小优先级越高)
.host("**.throttle.org") // 匹配需要限流的域名
.and().path("/get") // 匹配 GET 请求路径
.filters { f ->
// 应用限流过滤器:1个令牌,1个令牌桶容量,10秒补充周期
f.filter(throttle.apply(1, 1, 10, TimeUnit.SECONDS))
}
.uri("http://httpbin.org:80") // 转发到目标服务
.metadata("key", "value") // 添加路由元数据
}
.build() // 构建路由配置
}
}java
import org.springframework.cloud.gateway.filter.factory.ThrottleGatewayFilterFactory;
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;
import java.util.concurrent.TimeUnit;
@Configuration
public class GatewayConfiguration {
@Bean
public RouteLocator customRouteLocator(
RouteLocatorBuilder builder,
ThrottleGatewayFilterFactory throttle) {
return builder.routes()
.route(r -> r.host("**.abc.org").and().path("/image/png")
.filters(f ->
f.addResponseHeader("X-TestHeader", "foobar"))
.uri("http://httpbin.org:80")
)
.route(r -> r.path("/image/webp")
.filters(f ->
f.addResponseHeader("X-AnotherHeader", "baz"))
.uri("http://httpbin.org:80")
.metadata("key", "value")
)
.route(r -> r.order(-1)
.host("**.throttle.org").and().path("/get")
.filters(f -> f.filter(throttle.apply(1,
1,
10,
TimeUnit.SECONDS)))
.uri("http://httpbin.org:80")
.metadata("key", "value")
)
.build();
}
}路由处理流程
以下流程图展示了请求在网关中的处理过程:
核心组件说明
RouteLocatorBuilder
RouteLocatorBuilder 是构建路由配置的核心工具类,提供了以下主要方法:
- routes():开始构建路由规则
- route():定义单个路由规则
- build():完成构建并返回
RouteLocator实例
路由谓词 (Route Predicates)
路由谓词用于匹配请求条件:
kotlin
// 主机名匹配(支持通配符)
r.host("**.abc.org")
// 路径匹配
r.path("/image/png")
// 组合条件(AND 逻辑)
r.host("**.abc.org").and().path("/image/png")
// 路由优先级
r.order(-1)过滤器 (Filters)
过滤器用于修改请求或响应:
kotlin
// 添加响应头
f.addResponseHeader("X-TestHeader", "foobar")
// 应用自定义过滤器(如限流)
f.filter(throttle.apply(1, 1, 10, TimeUnit.SECONDS))高级特性
谓词逻辑组合
流式 API 支持复杂的谓词逻辑组合:
kotlin
@Bean
fun advancedRouteLocator(builder: RouteLocatorBuilder): RouteLocator {
return builder.routes()
.route { r ->
r.path("/api/**") // 匹配 API 路径
.and().method("GET", "POST") // 并且是 GET 或 POST 方法
.and().header("X-API-Key") // 并且包含 API 密钥头
.or().path("/public/**") // 或者是公共路径
.filters { f ->
f.addRequestHeader("X-Gateway", "spring-cloud")
.addResponseHeader("X-Processed-By", "gateway")
}
.uri("lb://backend-service") // 负载均衡到后端服务
}
.build()
}元数据配置
可以为路由添加元数据,用于监控和调试:
kotlin
.route { r ->
r.path("/metrics/**")
.filters { f -> f.stripPrefix(1) } // 去除路径前缀
.uri("http://monitoring-service:8080")
.metadata("service-type", "monitoring") // 服务类型元数据
.metadata("version", "1.0") // 版本信息
.metadata("timeout", 5000) // 超时配置
}实际业务应用场景
1. 电商平台 API 网关
kotlin
@Bean
fun ecommerceRouteLocator(builder: RouteLocatorBuilder): RouteLocator {
return builder.routes()
// 用户服务路由
.route { r ->
r.path("/api/users/**")
.filters { f ->
f.stripPrefix(2) // 去除 /api/users 前缀
.addRequestHeader("Service", "user-service")
}
.uri("lb://user-service") // 负载均衡到用户服务
}
// 订单服务路由
.route { r ->
r.path("/api/orders/**")
.filters { f ->
f.stripPrefix(2)
.addRequestHeader("Service", "order-service")
.circuitBreaker { cb -> cb.name("order-cb") } // 熔断保护
}
.uri("lb://order-service")
}
// 支付服务路由(需要特殊安全处理)
.route { r ->
r.path("/api/payments/**")
.and().header("Authorization") // 必须包含认证头
.filters { f ->
f.stripPrefix(2)
.addRequestHeader("Service", "payment-service")
.addRequestHeader("X-Security-Level", "high")
}
.uri("lb://payment-service")
}
.build()
}2. 内容分发网络 (CDN)
kotlin
@Bean
fun cdnRouteLocator(builder: RouteLocatorBuilder): RouteLocator {
return builder.routes()
// 静态资源路由
.route { r ->
r.path("/static/**")
.filters { f ->
f.addResponseHeader("Cache-Control", "max-age=3600") // 缓存 1 小时
.addResponseHeader("X-CDN-Cache", "HIT")
}
.uri("http://static-file-server:8080")
}
// 图片优化路由
.route { r ->
r.path("/images/**")
.and().header("Accept", "image/webp") // 支持 WebP 格式的客户端
.filters { f ->
f.addResponseHeader("X-Image-Format", "webp")
.addResponseHeader("Content-Type", "image/webp")
}
.uri("http://image-optimizer:8080")
}
.build()
}最佳实践
以下是使用流式 API 的最佳实践建议:
1. 路由优先级管理
kotlin
// 使用 order() 方法明确指定路由优先级
.route { r ->
r.order(-100) // 最高优先级
.path("/api/admin/**")
// ... 管理员路由配置
}
.route { r ->
r.order(0) // 默认优先级
.path("/api/**")
// ... 普通 API 路由配置
}2. 过滤器链优化
kotlin
.filters { f ->
f.addRequestHeader("X-Request-ID", UUID.randomUUID().toString()) // 请求追踪
.addRequestHeader("X-Gateway-Time", Instant.now().toString()) // 网关时间戳
.circuitBreaker { cb -> cb.name("default-cb") } // 熔断保护
.retry { retry -> retry.retries(3) } // 重试机制
.addResponseHeader("X-Response-Time", "#{T(System).currentTimeMillis()}") // 响应时间
}3. 配置模块化
kotlin
@Configuration
class GatewayRoutesConfiguration {
@Bean
fun userServiceRoutes(builder: RouteLocatorBuilder): RouteLocator {
return builder.routes()
.route(this::configureUserRoute)
.build()
}
@Bean
fun orderServiceRoutes(builder: RouteLocatorBuilder): RouteLocator {
return builder.routes()
.route(this::configureOrderRoute)
.build()
}
private fun configureUserRoute(r: RouteSpec): Route {
return r.path("/users/**")
.filters { f -> f.stripPrefix(1) }
.uri("lb://user-service")
.build()
}
private fun configureOrderRoute(r: RouteSpec): Route {
return r.path("/orders/**")
.filters { f -> f.stripPrefix(1) }
.uri("lb://order-service")
.build()
}
}常见问题
Q: 如何调试路由配置?
可以通过以下方式调试路由配置:
启用调试日志:
yamllogging: level: org.springframework.cloud.gateway: DEBUG添加自定义过滤器记录日志:
kotlin.filters { f -> f.filter { exchange, chain -> logger.info("Processing request: ${exchange.request.uri}") chain.filter(exchange) } }
Q: 路由优先级如何确定?
路由优先级规则:
- 数字越小,优先级越高
- 未指定 order 的路由默认优先级为 0
- 相同优先级的路由按定义顺序执行
Q: 如何处理路由冲突?
避免路由冲突的方法:
- 使用更具体的谓词条件
- 合理设置路由优先级
- 使用
.and()组合多个条件增加精确性
总结
Spring Cloud Gateway 的流式 Java API 提供了强大而灵活的路由配置能力。通过编程方式配置路由,我们可以:
- ✅ 实现复杂的路由逻辑
- ✅ 支持动态路由配置
- ✅ 提供类型安全的配置方式
- ✅ 便于测试和维护
在实际项目中,建议结合配置文件和编程配置两种方式,将简单的路由规则放在配置文件中,复杂的业务逻辑使用流式 API 实现。