Spring Cloud Gateway:构建API网关
在微服务架构中,随着服务数量的激增,如何高效地管理API接口、保障系统安全、实现流量控制成为亟待解决的问题。API网关作为微服务架构的门户,承担着请求路由、负载均衡、认证授权、限流熔断等重要职责。Spring Cloud Gateway作为Spring生态系统中的新一代API网关解决方案,基于响应式编程模型,提供了强大的功能和优秀的性能。本文将全面深入地讲解Spring Cloud Gateway的核心概念、实战应用、高级特性及最佳实践,包含60+代码示例,帮助开发者构建企业级的API网关系统。
一、API网关的核心价值与演进
在深入学习Spring Cloud Gateway之前,我们首先需要理解API网关在微服务架构中的角色和价值,以及网关技术的发展历程。
1. 微服务架构中的API网关
随着单体应用向微服务架构演进,应用被拆分为多个独立部署的服务,每个服务都有自己的API接口。这种架构带来了灵活性和可扩展性,但也引入了新的挑战:
- 接口管理复杂:客户端需要记住多个服务的地址和端口,随着服务数量增加,维护成本急剧上升
- 认证授权分散:每个服务都需要实现认证授权逻辑,导致重复开发和不一致性
- 跨域问题突出:前端应用可能需要调用多个不同域名的服务,面临浏览器的跨域限制
- 协议转换需求:内部服务可能使用不同的协议(如gRPC),需要转换为HTTP供外部访问
- 流量控制缺失:缺乏统一的流量控制、限流熔断机制,难以保障系统稳定性
- 监控日志分散:每个服务独立记录日志,难以进行全局监控和问题排查
API网关作为客户端与微服务之间的中间层,解决了上述问题,其核心功能包括:
- 统一入口:为所有API提供单一入口点,简化客户端调用
- 路由转发:根据请求路径、方法等规则将请求转发到相应的微服务
- 认证授权:集中处理认证授权,避免重复开发
- 限流熔断:保护后端服务,防止过载
- 监控日志:集中记录请求日志,便于监控和排查问题
- 协议转换:支持不同协议之间的转换
- 缓存静态资源:减轻后端服务压力
- 跨域处理:统一解决跨域问题
2. API网关技术演进
API网关技术经历了多个发展阶段:
- 第一代网关:如Netflix Zuul 1.x,基于Servlet同步阻塞模型,性能有限
- 第二代网关:如Spring Cloud Gateway、Netflix Zuul 2.x,基于Netty非阻塞响应式模型,性能大幅提升
- 专用网关:如Kong、Nginx Plus,基于Nginx,性能优异但灵活性稍差
Spring Cloud Gateway相比其他网关的优势:
- 响应式编程:基于Spring WebFlux和Netty,非阻塞,支持高并发
- Spring生态集成:与Spring Cloud服务发现、配置中心等组件无缝集成
- 动态路由:支持动态配置路由规则,无需重启服务
- 强大的过滤器:内置丰富的过滤器,支持自定义过滤器
- 精确的路由匹配:基于多种条件(路径、方法、Header等)进行路由匹配
- 易于扩展:采用插件化设计,易于扩展新功能
性能对比:根据Spring官方测试,在相同硬件条件下,Spring Cloud Gateway的吞吐量是Zuul 1.x的3倍以上,延迟降低50%以上,非常适合高并发场景。
3. Spring Cloud Gateway核心优势
Spring Cloud Gateway之所以成为微服务架构的首选网关解决方案,源于其以下核心优势:
- 非阻塞响应式:基于Reactor和Netty,能够高效处理大量并发连接,资源利用率更高
- 功能完备:内置路由、过滤、负载均衡、熔断、限流等核心功能
- 灵活配置:支持YAML/Properties配置文件、Java代码、动态配置等多种配置方式
- 强大的路由能力:支持多种路由断言方式,满足复杂的路由需求
- 丰富的过滤器:内置数十种过滤器,覆盖大部分常见场景,同时支持自定义过滤器
- 服务发现集成:自动从服务注册中心(如Eureka、Nacos)获取服务地址,实现动态路由
- 配置中心集成:与Spring Cloud Config集成,支持路由规则的动态更新
- 监控与追踪:与Spring Boot Actuator、Sleuth/Zipkin集成,提供完善的监控和追踪能力
适用场景:Spring Cloud Gateway适用于各种规模的微服务架构,特别适合对性能要求高、需要灵活扩展的场景,如电商平台、支付系统、API服务平台等。
二、Spring Cloud Gateway核心概念与工作原理
要熟练使用Spring Cloud Gateway,首先需要理解其核心概念和工作原理,这是深入学习和应用的基础。
1. 核心概念
Spring Cloud Gateway有三个核心概念,理解这三个概念是掌握Gateway的关键:
- 路由(Route):路由是网关的基本构建块,由ID、目标URI、断言集合和过滤器集合组成。当断言集合为真时,路由匹配成功,请求将被转发到目标URI。
- 断言(Predicate):断言是Java 8的Function Predicate,用于匹配HTTP请求的各种属性,如路径、方法、Header、参数等。断言可以组合使用,实现复杂的匹配规则。
- 过滤器(Filter):过滤器用于在请求被路由前后修改请求或响应。Spring Cloud Gateway的过滤器分为两种:GatewayFilter(针对特定路由)和GlobalFilter(针对所有路由)。
这三个核心概念的关系可以概括为:当请求到达网关时,网关通过断言判断请求是否匹配某个路由,如果匹配,则经过该路由的过滤器链处理后,转发到目标服务。
2. 工作原理
Spring Cloud Gateway的工作流程如下:
- 客户端发送请求:客户端向Spring Cloud Gateway发送HTTP请求
- 请求进入DispatcherHandler:请求被DispatcherHandler接收,这是Spring Cloud Gateway的核心处理器
- 查找匹配的路由:DispatcherHandler将请求交给RoutePredicateHandlerMapping,后者根据断言查找匹配的路由
- 执行过滤器链:如果找到匹配的路由,请求将经过该路由的过滤器链(包括GlobalFilter和GatewayFilter)
- 请求转发:过滤器链执行完成后,请求被转发到目标服务
- 处理响应:目标服务返回响应,响应再次经过过滤器链(反向)处理后返回给客户端
![Spring Cloud Gateway工作流程图]
关键技术点:
- Spring Cloud Gateway基于Netty服务器,使用非阻塞I/O模型,能够高效处理并发请求
- 采用响应式编程模型(Reactive Programming),使用Reactor库处理异步数据流
- 过滤器链采用责任链模式,每个过滤器可以决定是否继续传递请求或直接返回响应
3. 路由断言工厂
Spring Cloud Gateway提供了多种内置的路由断言工厂(Route Predicate Factory),用于创建不同类型的断言:
断言工厂 | 说明 | 示例 |
---|---|---|
PathRoutePredicateFactory | 匹配请求路径 | Path=/users/** |
MethodRoutePredicateFactory | 匹配HTTP方法 | Method=GET,POST |
HeaderRoutePredicateFactory | 匹配请求头 | Header=X-Request-Id, \d+ |
QueryRoutePredicateFactory | 匹配请求参数 | Query=page, \d+ |
CookieRoutePredicateFactory | 匹配Cookie | Cookie=sessionId, ^[a-z0-9]+$ |
HostRoutePredicateFactory | 匹配主机名 | Host=**.example.com |
PortRoutePredicateFactory | 匹配端口 | Port=8080 |
RemoteAddrRoutePredicateFactory | 匹配远程地址 | RemoteAddr=192.168.1.0/24 |
WeightRoutePredicateFactory | 基于权重路由 | Weight=group1, 8 |
AfterRoutePredicateFactory | 在指定时间之后 | After=2023-10-01T00:00:00+08:00 |
BeforeRoutePredicateFactory | 在指定时间之前 | Before=2023-12-31T23:59:59+08:00 |
BetweenRoutePredicateFactory | 在两个时间之间 | Between=2023-10-01T00:00:00+08:00, 2023-12-31T23:59:59+08:00 |
这些断言工厂可以组合使用,实现复杂的路由匹配规则。
4. 过滤器工厂
Spring Cloud Gateway提供了丰富的过滤器工厂(GatewayFilter Factory),用于在请求处理过程中修改请求或响应:
过滤器工厂 | 说明 | 示例 |
---|---|---|
AddRequestHeaderGatewayFilterFactory | 添加请求头 | AddRequestHeader=X-Request-Id, 123 |
AddResponseHeaderGatewayFilterFactory | 添加响应头 | AddResponseHeader=X-Response-Id, 456 |
RewritePathGatewayFilterFactory | 重写路径 | RewritePath=/api/(?<segment>.*), /$\{segment} |
SetPathGatewayFilterFactory | 设置路径 | SetPath=/{segment} |
RedirectToGatewayFilterFactory | 重定向 | RedirectTo=302, https://example.com |
RemoveRequestHeaderGatewayFilterFactory | 移除请求头 | RemoveRequestHeader=X-Request-Id |
RemoveResponseHeaderGatewayFilterFactory | 移除响应头 | RemoveResponseHeader=X-Response-Id |
RequestRateLimiterGatewayFilterFactory | 请求限流 | RequestRateLimiter=redis-rate-limiter.replenishRate=10, redis-rate-limiter.burstCapacity=20 |
CircuitBreakerGatewayFilterFactory | 熔断 | CircuitBreaker=myCircuitBreaker |
RetryGatewayFilterFactory | 重试 | Retry=retries=3, statuses=BAD_GATEWAY |
SetRequestHostHeaderGatewayFilterFactory | 设置请求主机头 | SetRequestHostHeader=example.com |
ForwardPathFilterFactory | 转发路径 | ForwardPath=/service |
除了这些针对特定路由的过滤器,Spring Cloud Gateway还提供了全局过滤器(GlobalFilter),如负载均衡过滤器、路由过滤器等,这些过滤器会应用于所有路由。
三、快速入门:搭建Spring Cloud Gateway基础环境
本节将通过实战演示,从零开始搭建Spring Cloud Gateway的基础环境,包括创建网关项目、配置简单路由、测试路由转发等。
1. 创建Spring Cloud Gateway项目
首先创建一个Spring Boot项目,添加Spring Cloud Gateway依赖。
(1)Maven依赖配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>spring-cloud-gateway-demo</artifactId>
<version>1.0.0</version>
<name>spring-cloud-gateway-demo</name>
<description>Spring Cloud Gateway Demo Project</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.5</spring-cloud.version>
</properties>
<dependencies>
<!-- Spring Cloud Gateway 核心依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Spring Boot Actuator 用于监控 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
注意:Spring Cloud Gateway依赖于Spring WebFlux,与Spring MVC不兼容。如果项目中已经引入了spring-boot-starter-web
(Spring MVC),需要将其排除,否则会导致冲突。
(2)创建启动类
package com.example.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
启动类非常简单,只需要添加@SpringBootApplication
注解即可,无需额外注解。
2. 配置第一个路由
Spring Cloud Gateway支持通过配置文件(YAML/Properties)或Java代码两种方式配置路由。我们先从配置文件方式开始。
(1)使用YAML配置路由
创建application.yml
配置文件:
server:
port: 8080 # 网关服务端口
spring:
cloud:
gateway:
routes:
# 第一个路由:匹配路径转发到httpbin.org
- id: httpbin_route # 路由唯一标识,建议与服务名相关
uri: https://httpbin.org # 目标服务地址
predicates: # 路由断言,判断请求是否匹配该路由
- Path=/httpbin/** # 路径匹配规则:以/httpbin/开头的路径
filters: # 路由过滤器,对请求/响应进行处理
- RewritePath=/httpbin/(?<segment>.*), /$\{segment} # 重写路径,去掉/httpbin前缀
- AddResponseHeader=X-Gateway, SpringCloudGateway # 添加响应头
# 第二个路由:匹配方法和路径转发到example.com
- id: example_route
uri: https://example.com
predicates:
- Path=/example/**
- Method=GET # 只匹配GET方法
filters:
- RewritePath=/example/(?<segment>.*), /$\{segment}
(2)配置说明
id
:路由的唯一标识符,在整个网关中必须唯一uri
:目标服务的地址,可以是HTTP地址、服务发现中的服务名(如lb://user-service
)predicates
:断言列表,所有断言都匹配时,路由才会生效filters
:过滤器列表,对请求和响应进行处理
上述配置定义了两个路由:
- 当请求路径以
/httpbin/
开头时,转发到https://httpbin.org
,并去掉/httpbin
前缀 - 当请求路径以
/example/
开头且为GET方法时,转发到https://example.com
,并去掉/example
前缀
3. 测试路由功能
启动Gateway应用,通过以下方式测试路由功能:
(1)测试httpbin路由
访问http://localhost:8080/httpbin/get
,该请求会被转发到https://httpbin.org/get
,返回类似以下响应:
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/7.68.0",
"X-Amzn-Trace-Id": "Root=1-634d9e8a-1f8a2b3c4d5e6f7g8h9i0j1k",
"X-Gateway": "SpringCloudGateway" // 我们添加的响应头
},
"origin": "127.0.0.1",
"url": "https://httpbin.org/get"
}
可以看到响应头中包含了我们通过过滤器添加的X-Gateway: SpringCloudGateway
,说明过滤器生效。
(2)测试example路由
访问http://localhost:8080/example
,该请求会被转发到https://example.com
,返回example.com的首页内容。
如果使用POST方法访问http://localhost:8080/example
,会返回404错误,因为我们的路由只匹配GET方法。
4. 使用Java代码配置路由
除了配置文件,Spring Cloud Gateway还支持通过Java代码配置路由,这种方式更灵活,适合复杂的路由规则。
创建一个配置类,定义路由:
package com.example.gateway.config;
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
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
// 配置百度路由
.route("baidu_route", r -> r
.path("/baidu/**") // 路径匹配
.filters(f -> f
.rewritePath("/baidu/(?<segment>.*)", "/${segment}") // 重写路径
.addResponseHeader("X-Source", "GatewayCodeConfig") // 添加响应头
)
.uri("https://www.baidu.com") // 目标地址
)
// 配置GitHub路由
.route("github_route", r -> r
.path("/github/**")
.and() // 组合多个断言
.method("GET", "POST") // 匹配GET和POST方法
.filters(f -> f
.rewritePath("/github/(?<segment>.*)", "/${segment}")
)
.uri("https://github.com")
)
.build();
}
}
重启应用后,测试新配置的路由:
- 访问
http://localhost:8080/baidu
,会转发到百度首页 - 访问
http://localhost:8080/github/spring-cloud
,会转发到https://github.com/spring-cloud
5. 查看路由信息
Spring Cloud Gateway提供了端点用于查看路由信息,方便调试和监控。
(1)配置端点
在application.yml
中添加以下配置,暴露路由端点:
management:
endpoints:
web:
exposure:
include: gateway,health,info # 暴露gateway端点
endpoint:
gateway:
enabled: true # 启用gateway端点
(2)访问路由端点
- 查看所有路由:
http://localhost:8080/actuator/gateway/routes
- 查看特定路由:
http://localhost:8080/actuator/gateway/routes/httpbin_route
- 刷新路由缓存:
POST http://localhost:8080/actuator/gateway/refresh
访问http://localhost:8080/actuator/gateway/routes
会返回所有路由的详细信息,包括ID、URI、断言、过滤器等。
四、路由断言实战
路由断言是Spring Cloud Gateway的核心功能之一,用于判断请求是否应该被转发到特定的服务。本节将详细介绍各种断言的使用方法和组合技巧。
1. 路径断言(Path)
路径断言是最常用的断言类型,根据请求路径进行匹配。
(1)基本用法
spring:
cloud:
gateway:
routes:
- id: path_route
uri: https://httpbin.org
predicates:
- Path=/users/**,/api/users/** # 匹配多个路径模式
filters:
- RewritePath=/api/(?<segment>.*), /$\{segment}
**
表示匹配任意数量的路径段,*
表示匹配单个路径段。
(2)路径变量提取
可以在路径中提取变量,供后续过滤器使用:
spring:
cloud:
gateway:
routes:
- id: path_variable_route
uri: https://httpbin.org
predicates:
- Path=/users/{id}/orders/{orderId} # 提取id和orderId变量
filters:
- AddRequestHeader=User-Id, {id} # 使用提取的id变量
- AddRequestHeader=Order-Id, {orderId} # 使用提取的orderId变量
2. 方法断言(Method)
根据HTTP请求方法进行匹配:
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://httpbin.org
predicates:
- Path=/posts/**
- Method=POST,PUT,PATCH # 匹配POST、PUT、PATCH方法
- id: get_route
uri: https://httpbin.org
predicates:
- Path=/users/**
- Method=GET # 只匹配GET方法
3. 请求头断言(Header)
根据请求头进行匹配,可以指定正则表达式:
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://httpbin.org
predicates:
- Path=/headers/**
- Header=X-API-Version, ^[1-3]$ # 匹配X-API-Version为1、2或3
- Header=Content-Type, application/json # 匹配Content-Type为application/json
测试:
# 匹配成功
curl -H "X-API-Version: 2" -H "Content-Type: application/json" http://localhost:8080/headers
# 匹配失败(X-API-Version不匹配)
curl -H "X-API-Version: 4" -H "Content-Type: application/json" http://localhost:8080/headers
4. 请求参数断言(Query)
根据请求参数进行匹配:
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://httpbin.org
predicates:
- Path=/query/**
- Query=page, \d+ # 匹配page参数为数字
- Query=size, 10|20|50 # 匹配size参数为10、20或50
- Query=sort # 匹配存在sort参数(不限制值)
测试:
# 匹配成功
curl http://localhost:8080/query?page=1&size=10&sort=asc
# 匹配失败(size不匹配)
curl http://localhost:8080/query?page=1&size=30&sort=asc
# 匹配失败(缺少sort参数)
curl http://localhost:8080/query?page=1&size=10
5. Cookie断言(Cookie)
根据Cookie进行匹配:
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://httpbin.org
predicates:
- Path=/cookies/**
- Cookie=sessionId, ^[a-zA-Z0-9]+$ # 匹配sessionId cookie值为字母数字
- Cookie=theme, dark|light # 匹配theme cookie值为dark或light
测试:
# 匹配成功
curl -b "sessionId=abc123; theme=dark" http://localhost:8080/cookies
# 匹配失败(sessionId格式不正确)
curl -b "sessionId=abc@123; theme=dark" http://localhost:8080/cookies
6. 主机断言(Host)
根据请求的主机名进行匹配:
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://httpbin.org
predicates:
- Host=api.example.com, *.service.example.com # 匹配指定主机名
- Path=/**
测试:
# 匹配成功
curl -H "Host: api.example.com" http://localhost:8080/get
# 匹配成功
curl -H "Host: user.service.example.com" http://localhost:8080/get
# 匹配失败
curl -H "Host: other.example.com" http://localhost:8080/get
7. 远程地址断言(RemoteAddr)
根据客户端IP地址进行匹配:
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: https://httpbin.org
predicates:
- Path=/remote/**
- RemoteAddr=192.168.1.0/24, 10.0.0.0/8 # 匹配指定网段的IP
测试:
# 从192.168.1.100访问会匹配成功
curl http://localhost:8080/remote
# 从其他网段IP访问会匹配失败
8. 时间断言(After/Before/Between)
根据时间进行匹配,适用于定时发布新功能等场景:
spring:
cloud:
gateway:
routes:
# 新功能路由,2023年10月1日后生效
- id: after_route
uri: https://httpbin.org/v2
predicates:
- Path=/new-feature/**
- After=2023-10-01T00:00:00+08:00[Asia/Shanghai]
# 旧功能路由,2023年10月1日前生效
- id: before_route
uri: https://httpbin.org/v1
predicates:
- Path=/old-feature/**
- Before=2023-10-01T00:00:00+08:00[Asia/Shanghai]
# 活动期间路由,在指定时间段内生效
- id: between_route
uri: https://httpbin.org/promotion
predicates:
- Path=/promotion/**
- Between=2023-11-11T00:00:00+08:00[Asia/Shanghai], 2023-11-11T23:59:59+08:00[Asia/Shanghai]
9. 权重断言(Weight)
基于权重的路由,用于灰度发布等场景:
spring:
cloud:
gateway:
routes:
# 新版本服务,权重80%
- id: weight_v2_route
uri: https://httpbin.org/v2
predicates:
- Path=/users/**
- Weight=userService, 80 # 权重80%
# 旧版本服务,权重20%
- id: weight_v1_route
uri: https://httpbin.org/v1
predicates:
- Path=/users/**
- Weight=userService, 20 # 权重20%
相同分组(这里是userService
)的路由权重之和应为100,请求会按照权重比例分配到不同的路由。
10. 断言组合使用
多个断言可以组合使用,只有所有断言都匹配时,路由才会生效:
spring:
cloud:
gateway:
routes:
- id: composite_route
uri: https://httpbin.org
predicates:
- Path=/composite/** # 路径匹配
- Method=GET # 方法匹配
- Header=X-API-Version, 2 # 请求头匹配
- Query=format, json # 请求参数匹配
- After=2023-01-01T00:00:00+08:00[Asia/Shanghai] # 时间匹配
filters:
- RewritePath=/composite/(?<segment>.*), /$\{segment}
测试:
# 所有断言都匹配,路由成功
curl -H "X-API-Version: 2" http://localhost:8080/composite/get?format=json
# 缺少X-API-Version头,路由失败
curl http://localhost:8080/composite/get?format=json
# 请求方法不匹配,路由失败
curl -X POST -H "X-API-Version: 2" http://localhost:8080/composite/get?format=json
五、过滤器实战
过滤器是Spring Cloud Gateway的另一个核心功能,用于在请求路由前后修改请求或响应。本节将详细介绍各种过滤器的使用方法和自定义过滤器的实现。
1. 内置过滤器使用
Spring Cloud Gateway提供了丰富的内置过滤器,覆盖了大部分常见场景。
(1)请求头过滤器
spring:
cloud:
gateway:
routes:
- id: header_filters_route
uri: https://httpbin.org
predicates:
- Path=/headers/**
filters:
- AddRequestHeader=X-Gateway-Id, gateway-01 # 添加请求头
- AddRequestHeadersIfNotPresent=X-Request-Source=gateway # 不存在时添加请求头
- RemoveRequestHeader=X-Unwanted-Header # 移除请求头
- AddResponseHeader=X-Response-Time, ${now} # 添加响应头
- RemoveResponseHeader=X-Internal-Header # 移除响应头
(2)路径过滤器
spring:
cloud:
gateway:
routes:
- id: path_filters_route
uri: https://httpbin.org
predicates:
- Path=/path/**
filters:
- RewritePath=/path/(?<segment>.*), /$\{segment} # 重写路径
- SetPath=/{segment} # 设置路径,使用路径变量
- PrefixPath=/api # 添加路径前缀
- StripPrefix=1 # 移除路径前缀(移除第一个 segment)
测试:
- 访问
http://localhost:8080/path/get
,经过RewritePath
后转发到https://httpbin.org/get
- 使用
PrefixPath=/api
时,访问http://localhost:8080/users
会转发到https://httpbin.org/api/users
- 使用
StripPrefix=1
时,访问http://localhost:8080/v1/users
会转发到https://httpbin.org/users
(3)重定向过滤器
spring:
cloud:
gateway:
routes:
- id: redirect_filter_route
uri: https://httpbin.org
predicates:
- Path=/old-path/**
filters:
- RedirectTo=301, https://httpbin.org/new-path # 永久重定向
- id: redirect_with_segment_route
uri: https://httpbin.org
predicates:
- Path=/legacy/{segment}
filters:
- RedirectTo=302, https://httpbin.org/new/{segment} # 临时重定向,使用路径变量
(4)参数过滤器
spring:
cloud:
gateway:
routes:
- id: parameter_filters_route
uri: https://httpbin.org
predicates:
- Path=/params/**
filters:
- AddRequestParameter=source, gateway # 添加请求参数
- RemoveRequestParameter=secret # 移除请求参数
(5)状态码过滤器
spring:
cloud:
gateway:
routes:
- id: status_filter_route
uri: https://httpbin.org
predicates:
- Path=/status/**
filters:
- SetStatus=404 # 强制设置响应状态码
- RewriteResponseStatus=200=201, 404=400 # 重写响应状态码
2. 全局过滤器
全局过滤器会应用于所有路由,适合实现认证授权、日志记录等全局功能。Spring Cloud Gateway内置了一些全局过滤器,如负载均衡过滤器、路由过滤器等。
(1)配置全局过滤器
spring:
cloud:
gateway:
default-filters: # 全局过滤器,应用于所有路由
- AddResponseHeader=X-Global-Filter, true
- RemoveResponseHeader=X-Powered-By
(2)自定义全局过滤器
实现GlobalFilter
和Ordered
接口创建自定义全局过滤器:
package com.example.gateway.filter;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import reactor.core.publisher.Mono;
/**
* 自定义全局日志过滤器,记录请求和响应信息
*/
@Configuration
public class GlobalLoggingFilterConfig {
@Bean
public GlobalFilter loggingGlobalFilter() {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
// 记录请求信息
System.out.println("Request: " + request.getMethod() + " " + request.getURI());
// 继续处理请求
return chain.filter(exchange)
// 处理响应
.then(Mono.fromRunnable(() -> {
System.out.println("Response: " + response.getStatusCode());
}));
};
}
@Bean
public OrderedGatewayFilter orderedLoggingFilter() {
// 创建一个有顺序的过滤器,Order值越小,优先级越高
return new OrderedGatewayFilter(loggingGlobalFilter(), Ordered.HIGHEST_PRECEDENCE + 1);
}
}
这个全局过滤器会记录所有请求的方法、URL和响应状态码。
3. 自定义路由过滤器
除了全局过滤器,我们还可以创建针对特定路由的自定义过滤器。
(1)创建简单的自定义过滤器
package com.example.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.List;
/**
* 自定义路由过滤器:计时过滤器,记录请求处理时间
*/
@Component
public class TimingGatewayFilterFactory extends AbstractGatewayFilterFactory<TimingGatewayFilterFactory.Config> {
// 配置类,用于存储过滤器参数
public static class Config {
private boolean enabled; // 是否启用计时
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
public TimingGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
// 如果未启用,直接继续
if (!config.isEnabled()) {
return chain.filter(exchange);
}
// 记录开始时间
long startTime = System.currentTimeMillis();
// 处理请求并记录时间
return chain.filter(exchange)
.then(Mono.fromRunnable(() -> {
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
System.out.println("Request duration: " + duration + "ms");
}));
};
}
// 用于配置参数的快捷方式
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("enabled");
}
}
(2)在路由中使用自定义过滤器
spring:
cloud:
gateway:
routes:
- id: custom_filter_route
uri: https://httpbin.org
predicates:
- Path=/timing/**
filters:
- RewritePath=/timing/(?<segment>.*), /$\{segment}
- name: Timing # 使用自定义过滤器,名称为类名去掉GatewayFilterFactory
args:
enabled: true # 启用计时
# 或者使用快捷方式
# - Timing=true
访问http://localhost:8080/timing/get
,控制台会输出请求处理时间。
(3)创建带多个参数的自定义过滤器
package com.example.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.Arrays;
import java.util.List;
/**
* 自定义API版本过滤器,验证请求中的API版本
*/
@Component
public class ApiVersionGatewayFilterFactory extends AbstractGatewayFilterFactory<ApiVersionGatewayFilterFactory.Config> {
public static class Config {
private String minVersion; // 最小版本
private String maxVersion; // 最大版本
private String headerName; // 版本头名称
// Getters and Setters
public String getMinVersion() { return minVersion; }
public void setMinVersion(String minVersion) { this.minVersion = minVersion; }
public String getMaxVersion() { return maxVersion; }
public void setMaxVersion(String maxVersion) { this.maxVersion = maxVersion; }
public String getHeaderName() { return headerName; }
public void setHeaderName(String headerName) { this.headerName = headerName; }
}
public ApiVersionGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String versionHeader = config.getHeaderName();
if (StringUtils.isEmpty(versionHeader)) {
versionHeader = "X-API-Version"; // 默认头名称
}
// 获取请求中的版本
String version = exchange.getRequest().getHeaders().getFirst(versionHeader);
if (StringUtils.isEmpty(version)) {
// 没有版本头,返回400错误
exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
return exchange.getResponse().setComplete();
}
// 验证版本是否在允许范围内(简化实现)
boolean valid = true;
if (!StringUtils.isEmpty(config.getMinVersion()) &&
compareVersions(version, config.getMinVersion()) < 0) {
valid = false;
}
if (!StringUtils.isEmpty(config.getMaxVersion()) &&
compareVersions(version, config.getMaxVersion()) > 0) {
valid = false;
}
if (!valid) {
// 版本无效,返回400错误
exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
return exchange.getResponse().setComplete();
}
// 版本有效,继续处理
return chain.filter(exchange);
};
}
// 简单的版本比较方法
private int compareVersions(String v1, String v2) {
String[] parts1 = v1.split("\\.");
String[] parts2 = v2.split("\\.");
int minLength = Math.min(parts1.length, parts2.length);
for (int i = 0; i < minLength; i++) {
int num1 = Integer.parseInt(parts1[i]);
int num2 = Integer.parseInt(parts2[i]);
if (num1 != num2) {
return Integer.compare(num1, num2);
}
}
return Integer.compare(parts1.length, parts2.length);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("minVersion", "maxVersion", "headerName");
}
}
在路由中使用:
spring:
cloud:
gateway:
routes:
- id: api_version_route
uri: https://httpbin.org
predicates:
- Path=/versioned/**
filters:
- RewritePath=/versioned/(?<segment>.*), /$\{segment}
- name: ApiVersion
args:
minVersion: 1.0
maxVersion: 2.0
headerName: X-API-Version
测试:
# 版本有效
curl -H "X-API-Version: 1.5" http://localhost:8080/versioned/get
# 版本太低
curl -H "X-API-Version: 0.9" http://localhost:8080/versioned/get
# 版本太高
curl -H "X-API-Version: 2.1" http://localhost:8080/versioned/get
# 缺少版本头
curl http://localhost:8080/versioned/get
4. 过滤器执行顺序
Spring Cloud Gateway的过滤器执行顺序由Ordered
接口的getOrder()
方法决定,Order值越小,执行越早。
过滤器的执行流程:
- 所有全局过滤器和路由过滤器按Order从小到大执行"pre"处理(请求被路由前)
- 请求被转发到目标服务
- 所有全局过滤器和路由过滤器按Order从大到小执行"post"处理(响应返回后)
// 示例:设置过滤器顺序
@Component
public class OrderedFilterExample implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// pre处理
System.out.println("OrderedFilterExample pre processing");
return chain.filter(exchange)
.then(Mono.fromRunnable(() -> {
// post处理
System.out.println("OrderedFilterExample post processing");
}));
}
@Override
public int getOrder() {
return 100; // 顺序值,越小越先执行pre处理,越晚执行post处理
}
}
最佳实践:
- 使用Spring定义的常量作为Order基准,如
Ordered.HIGHEST_PRECEDENCE
、Ordered.LOWEST_PRECEDENCE
- 认证过滤器应设置较高优先级(小Order值),确保在其他过滤器之前执行
- 日志记录过滤器通常设置中等优先级
- 响应处理过滤器设置较低优先级(大Order值)
六、服务发现与动态路由
在微服务架构中,服务实例的地址可能会动态变化(如扩缩容、故障迁移),Spring Cloud Gateway可以与服务发现组件集成,实现动态路由。
1. 与Eureka集成
Eureka是Spring Cloud生态中常用的服务注册中心,Spring Cloud Gateway可以自动从Eureka获取服务地址。
(1)添加Eureka客户端依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
(2)配置Eureka和Gateway
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
discovery:
locator:
enabled: true # 启用服务发现定位器
lower-case-service-id: true # 服务ID转为小写
eureka:
client:
serviceUrl:
defaultZone: http://eureka-server1:8761/eureka/,http://eureka-server2:8762/eureka/ # Eureka服务器地址
fetch-registry: true
register-with-eureka: true
instance:
preferIpAddress: true # 注册时使用IP地址
(3)自动路由规则
当spring.cloud.gateway.discovery.locator.enabled=true
时,Gateway会自动创建路由:
- 路由路径格式:
/{serviceId}/**
- 转发到:
lb://{serviceId}
(lb表示负载均衡)
例如,名为user-service
的服务,会自动创建路由:
- 请求
http://gateway:8080/user-service/users/1
会转发到user-service
服务的/users/1
接口
(4)自定义服务发现路由
自动路由规则可能不满足需求,我们可以自定义基于服务发现的路由:
spring:
cloud:
gateway:
routes:
# 用户服务路由
- id: user_service_route
uri: lb://user-service # lb://表示使用负载均衡,user-service是服务名
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1 # 移除/api前缀,转发到/user-service/users/**
# 订单服务路由
- id: order_service_route
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=1
这样,请求http://gateway:8080/api/users/1
会转发到user-service
服务的/users/1
接口。
2. 与Nacos集成
Nacos是阿里巴巴开源的服务发现和配置管理工具,也可以与Spring Cloud Gateway集成。
(1)添加Nacos依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.2.7.RELEASE</version>
</dependency>
(2)配置Nacos和Gateway
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: nacos-server:8848 # Nacos服务器地址
username: nacos
password: nacos
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
路由配置与Eureka集成类似,可以使用自动路由或自定义路由。
3. 负载均衡配置
Spring Cloud Gateway与Spring Cloud LoadBalancer集成,提供负载均衡功能。
(1)负载均衡策略配置
spring:
cloud:
loadbalancer:
ribbon:
enabled: false # 禁用Ribbon,使用Spring Cloud LoadBalancer
cache:
enabled: true
ttl: 30s # 服务列表缓存时间
retry:
enabled: true # 启用重试
(2)自定义负载均衡策略
创建自定义负载均衡器配置:
package com.example.gateway.config;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* 自定义负载均衡配置
*/
@Configuration
public class LoadBalancerConfig {
// 为user-service服务配置随机负载均衡策略
@Bean
ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(loadBalancerClientFactory
.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}
在主配置类中指定应用:
@SpringBootApplication
@LoadBalancerClient(name = "user-service", configuration = LoadBalancerConfig.class)
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
4. 动态路由配置
Spring Cloud Gateway支持通过配置中心动态更新路由规则,无需重启网关服务。
(1)与Spring Cloud Config集成
添加Config Client依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
创建bootstrap.yml
配置:
spring:
application:
name: api-gateway
profiles:
active: dev
cloud:
config:
uri: http://config-server:8888 # 配置服务器地址
label: main
在配置仓库中添加网关配置(api-gateway-dev.yml
):
spring:
cloud:
gateway:
routes:
- id: user_service_route
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
(2)使用Spring Cloud Bus实现动态刷新
添加Bus依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
配置RabbitMQ:
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
management:
endpoints:
web:
exposure:
include: bus-refresh,health,info
当配置仓库中的路由规则变更后,发送POST请求刷新:
curl -X POST http://localhost:8080/actuator/bus-refresh
七、安全与认证授权
API网关作为系统的入口,负责统一的安全控制,包括认证、授权、HTTPS配置等。
1. HTTPS配置
为网关配置HTTPS,确保传输安全:
(1)生成SSL证书
# 生成自签名证书
keytool -genkeypair -alias gateway-ssl -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore gateway.p12 -validity 3650
将生成的gateway.p12
文件放在src/main/resources
目录下。
(2)配置HTTPS
server:
port: 8443 # HTTPS默认端口
ssl:
enabled: true
key-store: classpath:gateway.p12 # 证书路径
key-store-password: 123456 # 证书密码
key-store-type: PKCS12
key-alias: gateway-ssl # 证书别名
(3)HTTP重定向到HTTPS
spring:
cloud:
gateway:
routes:
- id: https_redirect_route
uri: https://localhost:8443
predicates:
- Path=/**
- Method=GET,POST,PUT,DELETE
filters:
- RedirectTo=301, https://${host}:8443/${path}
或者使用HttpToHttpsRedirectFilter
:
@Configuration
public class HttpsRedirectConfig {
@Bean
public RouteLocator httpsRedirectRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("http_redirect_to_https", r -> r
.scheme("http")
.filters(f -> f.redirect(301, "https://${host}:8443/${path}?${query}"))
.uri("https://localhost:8443"))
.build();
}
}
2. 基于JWT的认证授权
使用JWT(JSON Web Token)实现API网关的认证授权:
(1)添加依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
(2)创建JWT工具类
package com.example.gateway.security;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.security.Key;
import java.util.Date;
import java.util.function.Function;
@Component
public class JwtTokenProvider {
@Value("${jwt.secret}")
private String secretKey;
@Value("${jwt.expiration}")
private long expiration;
// 生成签名密钥
private Key getSigningKey() {
byte[] keyBytes = secretKey.getBytes();
return Keys.hmacShaKeyFor(keyBytes);
}
// 从令牌中提取用户名
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
// 从令牌中提取过期时间
public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
// 从令牌中提取声明
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
// 提取所有声明
private Claims extractAllClaims(String token) {
return Jwts
.parserBuilder()
.setSigningKey(getSigningKey())
.build()
.parseClaimsJws(token)
.getBody();
}
// 检查令牌是否过期
private Boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
// 验证令牌
public Boolean validateToken(String token, String username) {
final String extractedUsername = extractUsername(token);
return (extractedUsername.equals(username) && !isTokenExpired(token));
}
// 验证令牌是否有效
public Boolean isValidToken(String token) {
try {
Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(token);
return !isTokenExpired(token);
} catch (Exception e) {
return false;
}
}
// 从令牌中提取角色
public String extractRole(String token) {
Claims claims = extractAllClaims(token);
return claims.get("role", String.class);
}
}
(3)创建认证过滤器
package com.example.gateway.filter;
import com.example.gateway.security.JwtTokenProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
@Configuration
public class AuthFilterConfig {
private final JwtTokenProvider jwtTokenProvider;
public AuthFilterConfig(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
@Bean
public GlobalFilter authGlobalFilter() {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
// 不需要认证的路径
List<String> publicPaths = List.of(
"/auth/login",
"/auth/register",
"/actuator/health",
"/swagger-ui.html"
);
String path = request.getURI().getPath();
// 检查是否是公开路径
if (publicPaths.stream().anyMatch(path::startsWith)) {
return chain.filter(exchange);
}
// 从请求头获取令牌
String token = request.getHeaders().getFirst("Authorization");
// 验证令牌
if (token == null || !token.startsWith("Bearer ")) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 移除Bearer前缀
token = token.substring(7);
// 验证令牌有效性
if (!jwtTokenProvider.isValidToken(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 从令牌中提取用户信息并添加到请求头
String username = jwtTokenProvider.extractUsername(token);
String role = jwtTokenProvider.extractRole(token);
ServerHttpRequest modifiedRequest = request.mutate()
.header("X-User-Name", username)
.header("X-User-Role", role)
.build();
ServerWebExchange modifiedExchange = exchange.mutate()
.request(modifiedRequest)
.build();
return chain.filter(modifiedExchange);
};
}
@Bean
public Ordered orderedAuthFilter() {
return new Ordered() {
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 10; // 较高优先级,确保在路由前认证
}
};
}
}
(4)配置JWT参数
jwt:
secret: your-secret-key-which-should-be-very-long-and-secure-for-production-environment
expiration: 86400000 # 24小时,单位毫秒
3. 基于Spring Security的认证
Spring Cloud Gateway可以与Spring Security集成,实现更复杂的认证授权功能。
(1)添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
(2)Spring Security配置
package com.example.gateway.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http
// 配置路径授权规则
.authorizeExchange()
.pathMatchers("/auth/**", "/actuator/health").permitAll() // 公开路径
.pathMatchers("/api/admin/**").hasRole("ADMIN") // 需要ADMIN角色
.pathMatchers("/api/users/**").hasAnyRole("USER", "ADMIN") // 需要USER或ADMIN角色
.anyExchange().authenticated() // 其他路径需要认证
.and()
// 配置OAuth2资源服务器(如果使用OAuth2)
.oauth2ResourceServer()
.jwt()
.and()
.and()
// 关闭CSRF(API网关通常不需要)
.csrf().disable()
.build();
}
}
(3)配置OAuth2 JWT
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://auth-server.example.com # OAuth2认证服务器地址
jwk-set-uri: ${spring.security.oauth2.resourceserver.jwt.issuer-uri}/.well-known/jwks.json
八、限流与熔断
为了保护后端服务,防止过载和故障扩散,API网关需要实现限流和熔断功能。
1. 基于Redis的限流
Spring Cloud Gateway可以与Redis结合实现分布式限流。
(1)添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
(2)配置Redis
spring:
redis:
host: redis-server
port: 6379
password: redis-password
timeout: 2000
(3)配置限流过滤器
spring:
cloud:
gateway:
routes:
- id: rate_limit_route
uri: https://httpbin.org
predicates:
- Path=/rate-limit/**
filters:
- RewritePath=/rate-limit/(?<segment>.*), /$\{segment}
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 # 令牌桶填充速率(每秒)
redis-rate-limiter.burstCapacity: 20 # 令牌桶容量
key-resolver: "#{@userKeyResolver}" # 限流键解析器
(4)自定义限流键解析器
package com.example.gateway.config;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;
@Configuration
public class RateLimitConfig {
/**
* 基于用户的限流键解析器
*/
@Bean
public KeyResolver userKeyResolver() {
return exchange -> {
// 从请求头获取用户名,没有则使用IP地址
String username = exchange.getRequest().getHeaders().getFirst("X-User-Name");
if (username != null) {
return Mono.just(username);
}
// 使用IP地址作为限流键
String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
return Mono.just(ip);
};
}
/**
* 基于路径的限流键解析器
*/
@Bean
public KeyResolver pathKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getPath().toString()
);
}
/**
* 基于服务的限流键解析器
*/
@Bean
public KeyResolver serviceKeyResolver() {
return exchange -> {
// 从路由中获取服务ID
String serviceId = exchange.getAttribute("org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_DESTINATION_SERVICE_ID_ATTR");
return Mono.justOrEmpty(serviceId);
};
}
}
(5)自定义限流响应
package com.example.gateway.config;
import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import reactor.core.publisher.Mono;
@Configuration
public class CustomRateLimiterConfig {
@Bean
public RedisRateLimiter customRedisRateLimiter() {
// 自定义限流响应
return new RedisRateLimiter(10, 20) {
@Override
public Mono<Response> isAllowed(String routeId, String id) {
return super.isAllowed(routeId, id)
.flatMap(response -> {
if (!response.isAllowed()) {
// 限流时返回429 Too Many Requests
return Mono.just(new Response(false, response.getRemaining(), response.getBurstCapacity()))
.doOnNext(r -> {
// 可以在这里记录限流日志
System.out.println("Rate limit exceeded for " + id + " on route " + routeId);
});
}
return Mono.just(response);
});
}
};
}
}
2. 熔断与降级
使用Resilience4j实现网关的熔断和降级功能。
(1)添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-reactor</artifactId>
</dependency>
(2)配置熔断过滤器
spring:
cloud:
gateway:
routes:
- id: circuit_breaker_route
uri: https://httpbin.org
predicates:
- Path=/circuit-breaker/**
filters:
- RewritePath=/circuit-breaker/(?<segment>.*), /$\{segment}
- name: CircuitBreaker
args:
name: httpbinCircuitBreaker # 熔断器名称
fallbackUri: forward:/fallback/httpbin # 降级 fallback 路径
(3)配置Resilience4j
resilience4j:
circuitbreaker:
instances:
httpbinCircuitBreaker:
slidingWindowSize: 10 # 滑动窗口大小
failureRateThreshold: 50 # 失败率阈值,超过则打开熔断器
waitDurationInOpenState: 10000 # 熔断器打开状态持续时间(毫秒)
permittedNumberOfCallsInHalfOpenState: 3 # 半开状态允许的调用次数
registerHealthIndicator: true # 注册健康指示器
timelimiter:
instances:
httpbinCircuitBreaker:
timeoutDuration: 3000 # 超时时间(毫秒)
(4)实现降级Fallback接口
package com.example.gateway.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/fallback")
public class FallbackController {
/**
* httpbin服务的降级处理
*/
@GetMapping("/httpbin/{path}")
public Mono<Map<String, Object>> httpbinFallback(@PathVariable String path) {
Map<String, Object> fallbackResponse = new HashMap<>();
fallbackResponse.put("status", "error");
fallbackResponse.put("message", "Service is temporarily unavailable, please try again later");
fallbackResponse.put("path", path);
fallbackResponse.put("from", "gateway-fallback");
return Mono.just(fallbackResponse);
}
}
3. 重试机制
配置请求重试,提高系统可用性:
spring:
cloud:
gateway:
routes:
- id: retry_route
uri: https://httpbin.org
predicates:
- Path=/retry/**
filters:
- RewritePath=/retry/(?<segment>.*), /$\{segment}
- name: Retry
args:
retries: 3 # 重试次数
statuses: BAD_GATEWAY, SERVICE_UNAVAILABLE # 需要重试的状态码
methods: GET,POST # 需要重试的方法
backoff:
firstBackoff: 1000ms # 第一次重试延迟
maxBackoff: 5000ms # 最大重试延迟
factor: 2 # 延迟因子
basedOnPreviousValue: false # 是否基于 previous backoff 计算
九、监控与日志
为了保障网关的稳定运行,需要完善的监控和日志系统。
1. 集成Spring Boot Actuator
Spring Boot Actuator提供了丰富的监控端点。
(1)配置Actuator
management:
endpoints:
web:
exposure:
include: health,info,gateway,metrics,prometheus,circuitbreakers
base-path: /actuator # 端点基础路径
endpoint:
health:
show-details: always # 显示健康详情
probes:
enabled: true
gateway:
enabled: true
metrics:
enabled: true
prometheus:
enabled: true
metrics:
export:
prometheus:
enabled: true
health:
livenessstate:
enabled: true
readinessstate:
enabled: true
(2)常用端点
- 健康检查:
/actuator/health
- 路由信息:
/actuator/gateway/routes
- 指标信息:
/actuator/metrics
- 熔断器状态:
/actuator/circuitbreakers
- Prometheus指标:
/actuator/prometheus
2. 集成Prometheus和Grafana
实现网关指标的可视化监控。
(1)添加Prometheus依赖
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
(2)配置Prometheus抓取
在Prometheus配置文件prometheus.yml
中添加:
scrape_configs:
- job_name: 'api-gateway'
metrics_path: '/actuator/prometheus'
scrape_interval: 5s
static_configs:
- targets: ['api-gateway:8080']
(3)创建Grafana仪表盘
导入Spring Cloud Gateway相关的仪表盘模板,或创建自定义仪表盘,监控以下关键指标:
- 请求吞吐量(
spring_cloud_gateway_requests_seconds_count
) - 请求延迟(
spring_cloud_gateway_requests_seconds_sum
、spring_cloud_gateway_requests_seconds_max
) - 路由请求数(按路由ID)
- 响应状态码分布
- 限流次数
- 熔断器状态
3. 日志配置
配置详细的日志,便于问题排查。
(1)配置日志级别
logging:
level:
root: INFO
org.springframework.cloud.gateway: INFO
org.springframework.cloud.gateway.route.RouteDefinitionLocator: INFO
org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping: INFO
reactor.netty.http.client: INFO # HTTP客户端日志
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
file:
name: logs/api-gateway.log # 日志文件路径
logback:
rollingpolicy:
max-file-size: 10MB # 单个日志文件大小
max-history: 7 # 日志保留天数
(2)自定义访问日志
spring:
cloud:
gateway:
httpclient:
wiretap: true # 启用WireTap日志
httpserver:
wiretap: true
metrics:
enabled: true # 启用指标
logging:
level:
reactor.netty.http.client.HttpClient: DEBUG
reactor.netty.http.server.HttpServer: DEBUG
(3)使用自定义日志过滤器
创建记录详细访问日志的过滤器:
package com.example.gateway.filter;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import reactor.core.publisher.Mono;
import java.time.Duration;
import java.time.Instant;
import java.util.UUID;
@Configuration
public class AccessLogFilterConfig {
@Bean
public GlobalFilter accessLogFilter() {
return (exchange, chain) -> {
// 记录请求开始时间
Instant start = Instant.now();
// 生成请求ID
String requestId = UUID.randomUUID().toString();
ServerHttpRequest request = exchange.getRequest()
.mutate()
.header("X-Request-Id", requestId)
.build();
exchange = exchange.mutate().request(request).build();
ServerHttpResponse response = exchange.getResponse();
// 记录访问日志
return chain.filter(exchange)
.then(Mono.fromRunnable(() -> {
Instant end = Instant.now();
long duration = Duration.between(start, end).toMillis();
String log = String.format(
"ACCESS LOG: requestId=%s, method=%s, path=%s, remoteAddress=%s, status=%s, duration=%dms",
requestId,
request.getMethodValue(),
request.getURI().getPath(),
request.getRemoteAddress(),
response.getStatusCode(),
duration
);
System.out.println(log);
// 实际应用中可以使用logger.info(log)
}));
};
}
@Bean
public Ordered orderedAccessLogFilter() {
return () -> Ordered.LOWEST_PRECEDENCE;
}
}
十、最佳实践与性能优化
基于生产环境经验,总结Spring Cloud Gateway的最佳实践和性能优化策略。
1. 路由配置最佳实践
(1)路由ID命名规范
采用{serviceId}-{function}
的命名方式,清晰标识路由用途:
spring:
cloud:
gateway:
routes:
- id: user-service-api # 用户服务API路由
- id: order-service-admin # 订单服务管理路由
(2)路由优先级设计
将更具体的路由放在前面,避免被通用路由匹配:
spring:
cloud:
gateway:
routes:
# 具体路由放在前面
- id: user-service-detail
uri: lb://user-service
predicates:
- Path=/api/users/{id:[0-9]+} # 匹配具体用户ID
# 通用路由放在后面
- id: user-service-all
uri: lb://user-service
predicates:
- Path=/api/users/**
(3)使用配置中心管理路由
生产环境建议使用Spring Cloud Config或Nacos等配置中心管理路由规则,便于集中管理和动态更新。
(4)路由分组管理
对路由进行分组,便于管理和筛选:
spring:
cloud:
gateway:
routes:
- id: user-service-route
uri: lb://user-service
predicates:
- Path=/api/users/**
- name: Weight
args:
group: user-group # 路由分组
weight: 100
2. 过滤器使用最佳实践
(1)过滤器职责单一
每个过滤器只负责一项功能,提高复用性和可维护性:
- 认证过滤器:只处理认证逻辑
- 日志过滤器:只处理日志记录
- 限流过滤器:只处理限流逻辑
(2)合理设置过滤器顺序
- 认证过滤器:最高优先级(小Order值)
- 日志过滤器:中等优先级
- 响应处理过滤器:低优先级(大Order值)
(3)避免在过滤器中执行耗时操作
过滤器在请求响应链中执行,耗时操作会直接影响网关性能:
// 不推荐:在过滤器中执行同步阻塞操作
return chain.filter(exchange)
.then(Mono.fromRunnable(() -> {
// 耗时操作,如同步数据库访问
saveToDatabase(exchange);
}));
// 推荐:使用异步操作
return chain.filter(exchange)
.then(Mono.fromCallable(() -> {
// 异步执行耗时操作
return asyncSaveToDatabase(exchange);
})).then();
3. 性能优化策略
(1)JVM参数优化
# 推荐JVM参数
-Xms2G -Xmx2G -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m
-XX:+UseG1GC -XX:MaxGCPauseMillis=200
-XX:+ParallelRefProcEnabled -XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/var/log/gateway/heapdump.hprof
(2)Netty配置优化
spring:
cloud:
gateway:
httpclient:
connect-timeout: 2000 # 连接超时时间
response-timeout: 5s # 响应超时时间
pool:
type: fixed # 连接池类型
max-connections: 500 # 最大连接数
acquire-timeout: 3000 # 获取连接超时时间
httpserver:
connection-timeout: 2s # 服务器连接超时时间
(3)启用压缩
server:
compression:
enabled: true
mime-types: application/json,application/xml,text/plain,text/css,application/javascript
min-response-size: 1024 # 最小压缩响应大小
(4)关闭不必要的功能
spring:
cloud:
gateway:
metrics:
enabled: false # 不需要监控时关闭
discovery:
locator:
enabled: false # 不使用自动路由时关闭
(5)水平扩展
单实例性能有限,生产环境建议部署多个网关实例,通过负载均衡器分发请求:
[客户端] → [负载均衡器(Nginx/Ingress)] → [Gateway实例1]
→ [Gateway实例2]
→ [Gateway实例3]
4. 高可用部署
(1)多实例部署
部署至少2个Gateway实例,避免单点故障。
(2)配置中心高可用
使用高可用的配置中心(如Config Server集群、Nacos集群)。
(3)服务发现高可用
服务注册中心(如Eureka集群、Nacos集群)必须高可用。
(4)限流熔断保护
配置合理的限流和熔断参数,防止网关被流量击垮。
(5)健康检查与自动恢复
配置健康检查,结合容器编排平台(如Kubernetes)实现自动恢复:
management:
endpoint:
health:
probes:
enabled: true
十一、常见问题与解决方案
在使用Spring Cloud Gateway过程中,可能会遇到各种问题,本节总结常见问题及解决方案。
1. 路由不生效
(1)症状
请求没有按照预期路由到目标服务,可能返回404错误。
(2)可能原因及解决方案
-
路由断言不正确:检查Path、Method等断言是否正确配置
# 错误示例:路径匹配错误 predicates: - Path=/api/user # 只能匹配精确路径,不能匹配子路径 # 正确示例 predicates: - Path=/api/user/** # 匹配所有子路径
-
路由顺序问题:具体路由被通用路由覆盖,调整路由顺序,将具体路由放在前面
-
服务发现配置问题:使用
lb://serviceId
时服务未注册到服务发现# 检查服务是否注册 curl http://eureka-server:8761/eureka/apps/user-service
-
过滤器修改路径导致不匹配:检查RewritePath、StripPrefix等过滤器是否正确配置
# 错误示例:重写路径后不匹配目标服务 filters: - RewritePath=/api/(?<segment>.*), /service/$\{segment} # 可能导致目标服务没有对应的路径 # 正确示例:根据目标服务路径调整 filters: - RewritePath=/api/(?<segment>.*), /$\{segment}
2. 跨域问题
(1)症状
前端请求报跨域错误:Access to fetch at '...' from origin '...' has been blocked by CORS policy
(2)解决方案
配置全局跨域:
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowed-origins: "*" # 允许的源,生产环境应指定具体域名
allowed-methods: "*" # 允许的方法
allowed-headers: "*" # 允许的头
allow-credentials: true # 是否允许 credentials
max-age: 3600 # 预检请求缓存时间
或使用Java代码配置:
@Configuration
public class CorsConfig {
@Bean
public WebFilter corsFilter() {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
response.getHeaders().add("Access-Control-Allow-Origin", "*");
response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.getHeaders().add("Access-Control-Allow-Headers", "*");
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Max-Age", "3600");
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
return chain.filter(exchange);
};
}
}
3. 性能问题
(1)症状
网关响应慢,吞吐量低,CPU或内存使用率高。
(2)解决方案
- 检查过滤器性能:移除不必要的过滤器,优化耗时的过滤器逻辑
- 调整Netty配置:增大连接池,调整超时时间
spring: cloud: gateway: httpclient: pool: max-connections: 1000
- JVM优化:调整JVM参数,避免频繁GC
- 水平扩展:增加网关实例数量,分担负载
- 启用压缩:减少网络传输数据量
- 检查后端服务:后端服务响应慢也会导致网关性能问题
4. 动态路由不生效
(1)症状
更新配置中心的路由规则后,网关没有加载新的路由。
(2)解决方案
-
触发配置刷新:发送POST请求到
/actuator/bus-refresh
curl -X POST http://gateway:8080/actuator/bus-refresh
-
检查配置中心连接:确保网关能正常连接配置中心
# 检查配置中心地址是否正确 spring: cloud: config: uri: http://config-server:8888
-
检查配置格式:确保路由配置格式正确,特别是缩进和语法
-
查看日志:检查网关日志,寻找配置加载失败的原因
# 查看配置加载日志 grep "RouteDefinitionLocator" logs/api-gateway.log
5. 熔断器不生效
(1)症状
后端服务故障时,网关没有触发熔断,仍然返回错误。
(2)解决方案
-
检查依赖:确保添加了正确的熔断器依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId> </dependency>
-
检查配置:确保熔断器名称和配置匹配
# 过滤器中配置的熔断器名称 filters: - name: CircuitBreaker args: name: httpbinCircuitBreaker # 熔断器配置必须使用相同的名称 resilience4j: circuitbreaker: instances: httpbinCircuitBreaker: # 必须与过滤器中名称一致
-
检查超时配置:确保超时时间设置合理
resilience4j: timelimiter: instances: httpbinCircuitBreaker: timeoutDuration: 3000 # 确保大于后端服务的正常响应时间
-
查看熔断器状态:通过Actuator端点检查熔断器状态
curl http://gateway:8080/actuator/circuitbreakers
十二、总结与展望
Spring Cloud Gateway作为Spring生态中的新一代API网关,凭借其响应式编程模型、丰富的功能和优异的性能,成为微服务架构中API网关的首选方案。本文全面介绍了Spring Cloud Gateway的核心概念、实战应用、高级特性和最佳实践,涵盖了从基础路由配置到高级安全控制的各个方面。
核心要点回顾
- 核心概念:路由(Route)、断言(Predicate)、过滤器(Filter)是Spring Cloud Gateway的三大核心组件
- 路由配置:支持YAML配置文件、Java代码、动态配置等多种方式,可基于路径、方法、头信息等多种条件进行路由
- 过滤器:提供丰富的内置过滤器,支持自定义过滤器,可在请求路由前后修改请求或响应
- 服务发现集成:与Eureka、Nacos等服务发现组件无缝集成,实现动态路由和负载均衡
- 安全控制:支持HTTPS、JWT认证、Spring Security集成,实现统一的安全管控
- 限流熔断:结合Redis实现分布式限流,使用Resilience4j实现熔断降级,保护后端服务
- 监控日志:与Spring Boot Actuator、Prometheus、Grafana集成,提供完善的监控和日志能力
未来发展趋势
随着云原生技术的发展,Spring Cloud Gateway也在不断演进:
- 更好的云原生集成:与Kubernetes Ingress、Service Mesh等云原生技术的集成将更加紧密
- 性能持续优化:进一步优化响应式编程模型,提升高并发场景下的性能
- 功能增强:增加更多开箱即用的功能,如API文档聚合、请求验证等
- 可观测性提升:增强监控指标,提供更丰富的追踪信息
- 安全性增强:集成更多安全功能,如WAF(Web应用防火墙)能力
实践建议
在实际项目中使用Spring Cloud Gateway时,建议:
- 从小处着手:先实现基本的路由功能,再逐步添加认证、限流等高级功能
- 重视性能:网关是系统入口,性能至关重要,需进行充分的性能测试和优化
- 安全优先:将安全控制放在首位,实现统一的认证授权机制
- 完善监控:建立全面的监控体系,及时发现和解决问题
- 高可用设计:确保网关本身的高可用,避免成为系统瓶颈
Spring Cloud Gateway为微服务架构提供了强大的API网关解决方案,掌握其核心功能和最佳实践,能够帮助开发者构建更可靠、更安全、更高效的分布式系统。随着技术的不断发展,Spring Cloud Gateway将继续发挥重要作用,成为连接客户端和微服务的关键基础设施。