一、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 # 目標服務的URIpredicates: # 斷言列表,用于匹配請求- 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: RequestRateLimiterargs: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_routeuri: 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_routeuri: lb://order-service # 使用負載均衡轉發到order-servicepredicates:- Path=/api/order/** # 匹配以/api/order/開頭的路徑filters:- StripPrefix=2 # 去除前兩級路徑,如/api/order/ → /- AddRequestHeader=X-Gateway-Header, GatewayValue # 添加請求頭# 路由2:基于Header的路由- id: version_routeuri: lb://user-servicepredicates:- Path=/api/user/**- Header=X-API-Version, v1 # 僅當請求頭X-API-Version為v1時匹配filters:- RewritePath=/api/user/(?<segment>.*), /v1/$\{segment} # 重寫路徑# 路由3:基于查詢參數的路由- id: query_routeuri: http://example.compredicates:- Path=/query/**- Query=token, \d+ # 必須包含token參數且為數字filters:- StripPrefix=1# 路由4:自定義白名單路由(不需要認證)- id: whitelist_routeuri: http://backend-servicepredicates:- 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 {@Beanpublic 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();}// 自定義過濾器示例@Componentpublic static class CustomFilter implements GatewayFilter {@Overridepublic 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_routeuri: lb://SERVICE-NAMEpredicates:- Path=/service/**
確保在項目中集成了服務發現客戶端,如 Eureka 或 Nacos。
2. 全局過濾器
全局過濾器應用于所有路由,常用于實現全局性的功能,如鑒權、日志記錄等。創建一個全局過濾器:
@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered {@Overridepublic 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");}));}@Overridepublic int getOrder() {return -1; // 過濾器的執行順序,數值越小優先級越高}
}
3. 限流
使用 RequestRateLimiter
過濾器實現請求限流,通常與 Redis 配合使用:
spring:cloud:gateway:routes:- id: rate_limit_routeuri: http://example.compredicates:- Path=/rate-limit/**filters:- name: RequestRateLimiterargs: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_routeuri: http://example.compredicates:- Path=/circuit-breaker/**filters:- name: CircuitBreakerargs:name: myCircuitBreakerfallbackUri: 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 的擴展能力,定制適合的路由與過濾策略,并通過監控與日志功能,確保網關的穩定運行與高效性能。