一、Spring Cloud Gateway 简介
Spring Cloud Gateway 是基于 Spring 5、Project Reactor 和 Spring Boot 2 构建的 API 网关,旨在为微服务架构提供一种简单而有效的路由管理方式。它取代了 Netflix Zuul,提供了更高效和更强大的网关解决方案。
核心特点:
- 反应式编程模型:基于 Project Reactor 的非阻塞高性能处理
- 路由管理:支持灵活的路由匹配规则
- 过滤器机制:提供全局和局部过滤器处理请求和响应
- 易于扩展:可通过自定义过滤器和路由器扩展功能
二、Spring Cloud Gateway 核心概念
1. 三大核心组件
- Route(路由):网关的基本构建块,定义了请求路径与服务之间的映射关系
- Predicate(断言):Java 8 的 Predicate,用于匹配 HTTP 请求中的任何内容(如 headers 或参数)
- Filter(过滤器):可以在请求被路由前后修改请求和响应的组件
2. 工作流程
- 客户端向 Spring Cloud Gateway 发出请求
- 如果 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler
- Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回
三、Spring Boot 项目中集成 Gateway
1. 添加依赖
在 Maven 项目的 pom.xml
文件中添加以下依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>4.3.0</version> <!-- 版本号根据实际情况选择 -->
</dependency>
对于 Gradle 项目,在 build.gradle
中添加:
implementation 'org.springframework.cloud:spring-cloud-starter-gateway:2.2.6.RELEASE'
2. 启用网关
在 Spring Boot 应用程序的入口类上,通常不需要特殊注解,因为 Spring Cloud Gateway 会自动配置。但如果你使用的是较新版本,可能需要确保有 @SpringBootApplication
注解:
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
四、Spring Cloud Gateway 的 YML 配置详解
Spring Cloud Gateway 的路由配置主要通过 application.yml
或 application.properties
文件完成。下面详细介绍 YML 配置文件的规则与使用。
1. 基本路由配置结构
spring:
cloud:
gateway:
routes:
- id: route_id # 路由的唯一标识符,必须唯一
uri: http://example.com # 目标服务的URI
predicates: # 断言列表,用于匹配请求
- Path=/example/** # 示例断言:匹配以/example/开头的路径
filters: # 过滤器列表,用于处理请求和响应
- StripPrefix=1 # 示例过滤器:去除路径中的第一层前缀
2. 配置项详细说明
2.1 路由 (Routes)
routes
是一个路由配置的数组,每个路由包含以下主要属性:
- id (必需): 路由的唯一标识符,用于标识和引用该路由
- uri (必需): 请求最终要被转发的目标地址
- 可以是普通的 HTTP/HTTPS URL,如
http://example.com
- 也可以使用服务发现机制,如
lb://SERVICE-NAME
(负载均衡)
- 可以是普通的 HTTP/HTTPS URL,如
- predicates (可选): 断言数组,用于判断请求是否符合路由条件
- filters (可选): 过滤器数组,用于在请求转发前后进行处理
- order (可选): 路由的优先级,数字越小优先级越高
2.2 断言 (Predicates)
断言用于匹配 HTTP 请求中的各种条件,常用的断言类型包括:
Path - 路径匹配
predicates: - Path=/api/** # 匹配以/api/开头的路径
Method - HTTP 方法匹配
predicates: - Method=GET,POST # 匹配 GET 或 POST 请求
Header - 请求头匹配
predicates: - Header=X-Request-Id, \d+ # 匹配包含 X-Request-Id 头且值为数字的请求
Query - 查询参数匹配
predicates: - Query=name, \d+ # 匹配包含 name 参数且值为数字的请求
Host - 主机名匹配
predicates: - Host=**.example.com # 匹配主机名为任意子域名.example.com 的请求
Before/After/Between - 时间匹配
predicates: - Before=2023-01-01T00:00:00+08:00[Asia/Shanghai] # 在指定时间之前匹配 - After=2023-01-01T00:00:00+08:00[Asia/Shanghai] # 在指定时间之后匹配 - Between=2023-01-01T00:00:00+08:00[Asia/Shanghai], 2023-12-31T23:59:59+08:00[Asia/Shanghai]
Cookie - Cookie 匹配
predicates: - Cookie=chocolate, ch.p # 匹配包含名为 chocolate 且值匹配正则 ch.p 的 Cookie
2.3 过滤器 (Filters)
过滤器用于在请求转发前后进行处理,分为两种类型:
- GatewayFilter - 单个路由的过滤器
- GlobalFilter - 全局过滤器,应用于所有路由
常用过滤器配置:
StripPrefix - 去除路径前缀
filters: - StripPrefix=1 # 去除路径中的第一层前缀
例如,请求
/api/service1/test
,配置StripPrefix=1
后,转发路径为/service1/test
RewritePath - 重写路径
filters: - RewritePath=/api/(?<segment>.*), /$\{segment} # 将 /api/xxx 重写为 /xxx
AddRequestHeader - 添加请求头
filters: - AddRequestHeader=X-Request-Foo, Bar # 添加请求头 X-Request-Foo: Bar
AddResponseHeader - 添加响应头
filters: - AddResponseHeader=X-Response-Foo, Bar # 添加响应头 X-Response-Foo: Bar
PrefixPath - 添加路径前缀
filters: - PrefixPath=/mypath # 为所有请求路径添加前缀 /mypath
RequestRateLimiter - 请求限流
filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 # 每秒允许的请求数 redis-rate-limiter.burstCapacity: 20 # 每秒最大允许的请求数 key-resolver: "#{@userKeyResolver}" # 限流键解析器
2.4 服务发现与负载均衡
当与 Spring Cloud DiscoveryClient (如 Eureka、Nacos) 集成时,可以使用服务发现功能:
spring:
cloud:
gateway:
routes:
- id: service_route
uri: lb://SERVICE-NAME # lb 表示负载均衡,SERVICE-NAME 是注册的服务名
predicates:
- Path=/service/**
filters:
- StripPrefix=1
- lb://SERVICE-NAME:使用负载均衡器将请求转发到名为 SERVICE-NAME 的服务实例
- discovery.locator.enabled=true:启用服务发现定位器,允许通过服务名动态路由
3. 完整配置示例
下面是一个综合性的配置示例,展示多种配置组合:
spring:
cloud:
gateway:
# 启用服务发现
discovery:
locator:
enabled: true # 启用服务发现
lower-case-service-id: true # 服务ID使用小写
# 全局CORS配置
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "*" # 允许所有源
allowedMethods: "*" # 允许所有HTTP方法
allowedHeaders: "*" # 允许所有请求头
# 路由配置
routes:
# 路由1:静态路径路由
- id: order_service_route
uri: lb://order-service # 使用负载均衡转发到order-service
predicates:
- Path=/api/order/** # 匹配以/api/order/开头的路径
filters:
- StripPrefix=2 # 去除前两级路径,如/api/order/ → /
- AddRequestHeader=X-Gateway-Header, GatewayValue # 添加请求头
# 路由2:基于Header的路由
- id: version_route
uri: lb://user-service
predicates:
- Path=/api/user/**
- Header=X-API-Version, v1 # 仅当请求头X-API-Version为v1时匹配
filters:
- RewritePath=/api/user/(?<segment>.*), /v1/$\{segment} # 重写路径
# 路由3:基于查询参数的路由
- id: query_route
uri: http://example.com
predicates:
- Path=/query/**
- Query=token, \d+ # 必须包含token参数且为数字
filters:
- StripPrefix=1
# 路由4:自定义白名单路由(不需要认证)
- id: whitelist_route
uri: http://backend-service
predicates:
- Path=/auth/login, /auth/register, /public/**
filters:
- StripPrefix=1
# 自定义白名单配置(可选,通过代码实现)
ignore:
whites:
- /auth/login
- /auth/register
- /**/v2/api-docs
- /public/**
4. 通过代码配置路由
除了通过 YML 文件配置路由,还可以通过 Java 代码配置,提供更高的灵活性:
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("path_route", r -> r.path("/get")
.uri("http://httpbin.org"))
.route("host_route", r -> r.host("*.myhost.org")
.uri("http://httpbin.org"))
.route("rewrite_route", r -> r.host("*.rewrite.org")
.filters(f -> f.rewritePath("/foo/(?<segment>.*)", "/${segment}"))
.uri("http://httpbin.org"))
.route("hystrix_route", r -> r.path("/hystrix")
.filters(f -> f.hystrix(config -> config.setName("mycmd").setFallbackUri("forward:/fallback")))
.uri("http://httpbin.org"))
.route("custom_filter_route", r -> r.path("/api/test/**")
.filters(f -> f.rewritePath("/api/test/(?<segment>.*)", "/${segment}")
.filter(new CustomFilter()))
.uri("lb://project-test"))
.build();
}
// 自定义过滤器示例
@Component
public static class CustomFilter implements GatewayFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 自定义过滤逻辑
System.out.println("Custom Filter executed");
return chain.filter(exchange);
}
}
}
五、高级配置与功能
1. 负载均衡
通过使用 lb://SERVICE-NAME
格式的 URI,Spring Cloud Gateway 可以与服务发现组件(如 Eureka、Nacos)集成,实现负载均衡:
spring:
cloud:
gateway:
routes:
- id: service_route
uri: lb://SERVICE-NAME
predicates:
- Path=/service/**
确保在项目中集成了服务发现客户端,如 Eureka 或 Nacos。
2. 全局过滤器
全局过滤器应用于所有路由,常用于实现全局性的功能,如鉴权、日志记录等。创建一个全局过滤器:
@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 在请求处理前执行的逻辑
System.out.println("Global Pre Filter executed");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
// 在请求处理后执行的逻辑
System.out.println("Global Post Filter executed");
}));
}
@Override
public int getOrder() {
return -1; // 过滤器的执行顺序,数值越小优先级越高
}
}
3. 限流
使用 RequestRateLimiter
过滤器实现请求限流,通常与 Redis 配合使用:
spring:
cloud:
gateway:
routes:
- id: rate_limit_route
uri: http://example.com
predicates:
- Path=/rate-limit/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 # 每秒允许的请求数
redis-rate-limiter.burstCapacity: 20 # 每秒最大允许的请求数
key-resolver: "#{@userKeyResolver}" # 限流键解析器,需在代码中定义
需要在代码中定义 key-resolver
Bean,例如基于用户 ID 限流:
@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}
4. 熔断与重试
结合 Resilience4j 或 Hystrix 实现熔断和重试机制:
spring:
cloud:
gateway:
routes:
- id: circuit_breaker_route
uri: http://example.com
predicates:
- Path=/circuit-breaker/**
filters:
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/fallback
六、日志监控与运维
1. 日志功能
Spring Cloud Gateway 提供了丰富的日志功能,可以记录请求和响应的详细信息,帮助进行故障排查和性能优化:
- 控制台日志:默认情况下,网关会将请求和响应信息输出到应用日志中
- 文件日志:配置日志框架(如 Logback、Log4j2)将日志输出到文件
- 集成 ELK:将日志发送到 Elasticsearch、Logstash 和 Kibana 进行集中管理和分析
2. 监控工具
使用监控工具对网关的性能和流量进行实时监控和统计:
- Spring Boot Actuator:提供健康检查、指标监控等功能
- Prometheus + Grafana:集成 Prometheus 收集指标,使用 Grafana 进行可视化展示
- Micrometer:与应用性能监控系统(如 Atlas、Datadog、New Relic)集成
七、最佳实践与常见问题
1. 最佳实践
- 合理设计路由规则:根据业务需求设计清晰、简洁的路由规则,避免过于复杂的断言组合
- 使用服务发现:与注册中心集成,实现动态路由和负载均衡,提高系统的弹性和可扩展性
- 实施安全策略:通过过滤器实现鉴权、防止 SQL 注入、XSS 等安全措施
- 监控与日志:实施全面的日志记录和监控,及时发现和解决问题
- 性能优化:利用缓存、限流和熔断机制,保障网关的高可用性和高性能
2. 常见问题
- 路由不生效:检查路由的
predicates
是否正确匹配请求,确保id
唯一,配置无误 - 性能瓶颈:合理配置线程池和连接数,使用异步非阻塞模型,避免阻塞操作
- 服务不可用:确保后端服务正常运行,与注册中心集成正确,负载均衡策略合适
- 跨域问题:通过
globalcors
配置正确处理跨域请求,或通过过滤器自定义跨域策略
八、总结
Spring Cloud Gateway 作为微服务架构中的重要组件,提供了强大而灵活的路由与过滤功能。通过本教程,您应该已经了解了如何集成 Spring Cloud Gateway、如何配置路由规则以及如何利用其丰富的功能来满足各种业务需求。
YML 配置文件是配置 Spring Cloud Gateway 路由的主要方式,通过合理配置 routes
、predicates
和 filters
,可以实现复杂的路由逻辑和请求处理。同时,结合服务发现、负载均衡、限流、熔断等高级功能,可以构建高可用、高性能的微服务网关。
在实际项目中,建议根据具体业务需求,结合 Spring Cloud Gateway 的扩展能力,定制适合的路由与过滤策略,并通过监控与日志功能,确保网关的稳定运行与高效性能。