Gateway路由網關詳解
一、Gateway路由網關:
Spring Cloud Gateway 是 Spring Cloud 生態中的 API 網關組件,專為微服務架構設計,基于響應式編程模型(Reactive Programming)構建,使用 Netty 作為運行時環境,提供動態路由、安全、監控、限流等核心功能。

Spring Cloud Gateway的設計理念和存在意義圍繞微服務架構的核心訴求展開,旨在解決分布式系統中 API 管理的復雜性,其核心目標可歸納為以下幾點:
1、統一流量治理入口:
|
意義 |
微服務架構中服務數量激增,直接暴露所有服務端點存在安全風險和管理混亂問題 |
|
方案 |
作為統一入口,收斂所有內部服務的 API 暴露,對外提供標準化的訪問路徑,屏蔽內部服務細節(如服務名、實例地址) |
2、動態化與可編程性:
|
設計理念 |
|
支持通過配置(YAML/Java DSL)或代碼動態定義路由規則、過濾器鏈,無需重啟服務。 結合 Spring Cloud Config 或 Nacos 等配置中心,實現路由規則的實時更新,適應服務擴縮容、灰度發布等場景。 |
3、深度集成 Spring 生態:
|
意義 |
與 Spring Cloud 組件(如服務發現、熔斷器、安全框架)無縫協作,降低技術棧復雜度 |
|
典型場景 |
自動從 Eureka/Nacos 獲取服務實例列表,實現動態路由。 整合 Sentinel 實現熔斷降級,或通過 Spring Security 集中鑒權。 |
4、非阻塞高性能架構:
|
設計理念 |
|
基于響應式編程模型(Reactive,使用 WebFlux 和 Reactor),采用非阻塞 I/O,避免傳統同步阻塞網關(如 Zuul 1.x)的線程資源瓶頸。 適應高并發、低延遲場景(如物聯網、實時通信),提升系統吞吐量。 |
5、靈活擴展與定制:
|
意義 |
通過過濾器鏈機制,允許開發者自定義邏輯(如限流算法、日志格式) |
|
擴展點 |
全局過濾器(Global Filter):適用于所有路由(如統一鑒權、日志記錄)。 路由過濾器(Route Filter):針對特定路由的定制邏輯(如路徑重寫、請求頭修改)。 |
6、云原生友好性:
|
設計目標 |
適配 Kubernetes、Service Mesh 等云原生環境 |
|
特性 |
輕量級部署,支持容器化。 與服務網格(如 Istio)互補,處理南北流量(網關)與東西流量(Sidecar)的分工協作。 |
二、Gateway核心概念:
1、Gateway三大核心:
|
Route(路由) |
路由是構建網關的基本模塊,由ID,目標URI,一系列的斷言和過濾器組成 |
|
Predicate(斷言) |
開發人員可以匹配HTTP請求中的所有內容(例如請求頭或請求參數),如果請求與斷言相匹配則進行路由 |
|
Filter(過濾) |
使用過濾器,可以在請求被路由前或者之后對請求進行修改 |
2、Gateway工作原理:
Spring Cloud Gateway 作為微服務架構的 API 網關,其核心處理流程為:當客戶端請求到達時,網關基于預設的路由規則(如路徑、請求頭等斷言條件)匹配目標服務,隨后通過過濾器(Filter)鏈對請求進行預處理(如鑒權、限流、路徑重寫),以非阻塞方式(底層基于 Netty 的非阻塞 I/O 模型處理連接,利用 Reactor 線程模型實現高并發)將請求轉發至后端服務;待服務響應后,再經后置過濾器加工(如修改響應頭、統一錯誤格式),最終將結果返回客戶端,全程依托 Spring WebFlux 的響應式模型實現高性能和動態路由能力。

三、實戰:
1、斷言重寫路由:
(1)、解耦客戶端與后端服務,提升系統靈活性。
(2)、統一 API 入口,簡化客戶端調用邏輯。
(3)、動態適配后端服務路徑,支持服務獨立演進。
(4)、集成負載均衡和服務發現,提升系統可用性。
(5)、集中管理安全與流量控制,降低維護成本。

網關配置文件bootstrap-one.yml:
#斷言重寫路由配置 # 假設有一個走網關請求 URL 是 http://localhost:9090/api/provider/v1/resource,根據上述配置: # 1、匹配: # 請求路徑 /api/provider/v1/resource 匹配 Path=/api/provider/** 斷言。 # 2、重寫路徑: # 使用 RewritePath 過濾器將路徑從 /api/provider/v1/resource 重寫為 /provider/v1/resource。 # 3、轉發: # 最終請求將被轉發到 lb://cloud-provider-service/provider/v1/resource。 # 對外暴露端口 server: port: 9090 spring: #項目名 application: name: cloud-gateway-service cloud: nacos: config: server-addr: localhost:8848 file-extension: yaml # namespace: 3fd40f6b-0bc9-4a59-8838-0a64269125b4 # context-path: /nacos # username: nacos # password: nacos discovery: server-addr: localhost:8848 # namespace: 3fd40f6b-0bc9-4a59-8838-0a64269125b4 # username: nacos # password: nacos #############################網關配置########################### gateway: # 服務路由配置(路由是構建網關的基本模塊,由ID,目標URI,一系列的斷言和過濾器組成) routes: # 路由的ID,沒有固定規則但要求唯一,建議配合服務名 - id: cloud-provider-service # 路由的地址,lb表示使用負載均衡(引入負載均衡依賴)到微服務,也可以使用http正常轉發 # uri: lb://服務注冊中心注冊的服務名稱 # uri: http://localhost:8080 uri: lb://cloud-provider-service #斷言工廠列表: predicates: - Path=/api/provider/** filters: # 重寫路由:使用 RewritePath 過濾器將路徑從 /api/provider/(?<segment>.*) 重寫為 /provider/$\{segment}。 # 內部訪問地址:http://localhost:8080/provider/** # 網關訪問地址:http://localhost:9090/api/provider/** - RewritePath=/api/provider/(?<segment>.*), /provider/$\{segment} - id: cloud-consumer-service uri: lb://cloud-consumer-service predicates: - Path=/api/consumer/** filters: - RewritePath=/api/consumer/(?<segment>.*), /consumer/$\{segment}
注:
使用lb做負載均衡需引入相關依賴
<!--負載均衡-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
2、令牌桶算法限流過濾器:
在微服務架構中,網關作為所有請求的入口點,承擔著路由、認證、安全等職責。隨著業務規模的擴大和用戶量的增長,請求流量會顯著增加,這可能導致后端服務過載,影響系統的穩定性和響應時間。在網關層進行限流過濾器的部署,可以有效保護后端服務,提升用戶體驗,優化資源分配,并增強系統的整體穩定性。通過這種方式,可以更好地應對高并發場景,確保系統的可靠性和性能。
(1)、網關層限流過濾器的優點:
1)、控制請求速率:平滑地控制請求發送速率,防止瞬時高流量沖擊系統。
2)、保障穩定性:避免后端服務過載,確保系統的穩定性和可用性。
3)、公平分配資源:合理分配系統資源,確保每個服務都能獲得公平的服務響應時間。
4)、支持突發流量:允許一定程度的突發流量,同時保持長期穩定的請求處理能力。
5)、靈活配置:可以根據業務需求動態調整限流策略,適應不同的應用場景。
(2)、Gateway-RequestRateLimiter限流的實現原理:
Spring Cloud Gateway 的 RequestRateLimiter 基于令牌桶算法實現分布式限流,其原理是:通過 redis-rate-limiter 集成 Redis,系統以固定速率(replenishRate,如每秒 5 個令牌)向令牌桶填充令牌,桶容量上限為 burstCapacity(如 10 個令牌),允許突發流量短時消耗積累的令牌;當每個請求到達時,網關通過 Redis 原子化操作(Lua 腳本)檢查當前請求的限流鍵(由 key-resolver 定義,如按 IP 生成唯一鍵)嘗試從桶中獲取令牌,若桶中存在可用令牌則放行并扣除令牌,否則觸發限流(返回 HTTP 429),借助 Redis 的分布式存儲和原子性特性,確保多網關實例間的限流狀態嚴格一致,實現高并發場景下精準、靈活的流量控制。
(3)、令牌桶算法與漏桶算法:
|
對比維度 |
令牌桶算法 |
漏桶算法 |
|
核心思想 |
以固定速率生成令牌,請求需獲取令牌才能通過。 |
以恒定速率處理請求,超出速率的請求排隊或丟棄。 |
|
流量特性 |
允許突發流量(桶內令牌可累積)。 |
強制平滑流量(恒定速率輸出,無法應對突發)。 |
|
實現復雜度 |
簡單(僅需管理令牌生成和消耗)。 |
較高(需維護請求隊列和漏出速率)。 |
|
適用場景 |
需要容忍突發流量的場景(如秒殺、API 突發調用)。 |
需嚴格限制請求速率的場景(如音視頻流控)。 |
|
資源利用率 |
高(突發期可快速消費累積令牌)。 |
低(嚴格限速可能導致帶寬浪費)。 |
|
典型工具 |
Spring Cloud Gateway、 Google Guava RateLimiter |
Nginx 限流模塊、 pache 的 mod_ratelimit |
(4)、相關實現:
1)、POM依賴:
|
特性 |
spring-boot-starter-data-redis-reactive |
spring-boot-starter-data-redis |
|
編程模型 |
響應式(Reactive) |
同步(Blocking) |
|
客戶端 |
Lettuce(強制) |
Lettuce/Jedis(可選) |
|
適用場景 |
高并發、非阻塞 I/O |
常規同步操作 |
<!-- Redis Reactive 依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
2)、YML配置文件:bootstrap-two.yml
集成Redis配置令牌桶限流機制:
指定令牌填充速度replenishRate、令牌桶容量burstCapacity、限流策略KeyResolver
#令牌桶算法限流過濾器 # 令牌桶的基本邏輯是: # 每個IP對應一個桶,桶里有令牌,每秒補充一定的令牌數,最多不超過桶的容量。當請求到來時,如果桶里有足夠的令牌,則允許通過并消耗一個令牌,否則拒絕。 # 對外暴露端口 server: port: 9090 spring: #項目名 application: name: cloud-gateway-service cloud: nacos: config: server-addr: localhost:8848 file-extension: yaml # namespace: 3fd40f6b-0bc9-4a59-8838-0a64269125b4 # context-path: /nacos # username: nacos # password: nacos discovery: server-addr: localhost:8848 # namespace: 3fd40f6b-0bc9-4a59-8838-0a64269125b4 # username: nacos # password: nacos #############################網關配置########################### gateway: # 服務路由配置(路由是構建網關的基本模塊,由ID,目標URI,一系列的斷言和過濾器組成) routes: # 路由的ID,沒有固定規則但要求唯一,建議配合服務名 - id: cloud-provider-service # 路由的地址,lb表示使用負載均衡(引入負載均衡依賴)到微服務,也可以使用http正常轉發 # uri: lb://服務注冊中心注冊的服務名稱 # uri: http://localhost:8080 uri: lb://cloud-provider-service #斷言工廠列表: predicates: - Path=/provider/** filters: # 限流過濾器 - name: RequestRateLimiter args: # 填充速率,每秒允許通過請求數 redis-rate-limiter.replenishRate: 5 # 令牌桶容量,系統允許的突發請求量,即短時間內可以處理的最大請求數 redis-rate-limiter.burstCapacity: 10 # bean,配置限流策略 key-resolver: '#{@ipKeyResolver}' - id: cloud-consumer-service uri: lb://cloud-consumer-service predicates: - Path=/consumer/** filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 5 redis-rate-limiter.burstCapacity: 10 key-resolver: '#{@ipKeyResolver}' # redis 配置 redis: host: localhost # 單機模式-host port: 6379 # 單機模式-端口 timeout: 3000 # 連接超時時間(毫秒) lettuce: # lettuce連接池 pool: max-active: 8 # 連接池最大連接數(使用負值表示沒有限制) max-wait: -1 # 連接池最大阻塞等待時間(使用負值表示沒有限制) max-idle: 8 # 連接池中的最大空閑連接 min-idle: 0 # 連接池中的最小空閑連接
3)、限流策略key-resolver配置:
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import reactor.core.publisher.Mono; import java.util.Objects; @Configuration public class RateLimitConfig { /** * 根據ip限流策略 * @return 限流策略 * */ @Bean @Primary // 設置默認解析器(多個KeyResolver策略需指定) public KeyResolver ipKeyResolver() { return exchange -> // 獲取請求的遠程地址(即客戶端IP地址),并確保不為null Mono.just(Objects.requireNonNull(exchange.getRequest() // 獲取遠程地址(InetSocketAddress) .getRemoteAddress()) // 獲取InetSocketAddress中的InetAddress對象 .getAddress() // 獲取客戶端的IP地址(以字符串形式返回) .getHostAddress()); } /** * 根據uri路徑限流策略 * @return 限流策略 */ @Bean() public KeyResolver uriKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getURI().getPath()); } }
4)、自定義過濾器進行IP限流處理:
聲明Cache進行IP黑名單緩存:
import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.util.concurrent.TimeUnit; /** * IP 黑名單緩存 * * Guava CacheBuilder: * 一、核心優點 * 1、高性能本地訪問:微秒級響應,適用于高頻讀取場景(如網關 IP 校驗) * 2、靈活過期策略:支持寫入后/訪問后雙維度自動過期 * 3、自動內存管理:基于 LRU 的容量限制(maximumSize)防止 OOM * 4、細粒度并發控制:通過 concurrencyLevel 優化鎖競爭 * 5、內置監控統計:通過 cache.stats() 獲取命中率、淘汰次數等指標 * 二、主要不足 * 1、單機局限性:集群環境下數據不一致,需額外同步機制 * 2、內存容量受限:大流量場景易觸發頻繁淘汰或 GC 壓力 * 3、無持久化能力:服務重啟后數據丟失,需冷啟動預熱 * 4、緩存穿透風險:未命中時可能穿透到后端系統 */ public class IpBlackCache { public static final Cache<String, Boolean> IP_CACHE = CacheBuilder.newBuilder() // 最大cache數量 100條 .maximumSize(100) // 寫入后300s過期 .expireAfterWrite(300, TimeUnit.SECONDS) // 不訪問 60s過期 .expireAfterAccess(60, TimeUnit.SECONDS) // 最多8個同時更新緩存的并發, 默認4 .concurrencyLevel(8) // 開啟cache統計 .recordStats() .build(); }
自定義過濾器進行IP限流處理:
import com.alibaba.fastjson.JSONObject; import com.iven.utils.IpBlackCache; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.HashMap; import java.util.Map; @Slf4j @Component public class GatewayIpRateLimiterFilter implements GlobalFilter, Ordered { /** * 過濾函數,用于處理每個請求 * @param exchange 服務器web交換對象,包含請求和響應 * @param chain 網關過濾鏈,用于執行下一個過濾器 * @return Mono<Void> 表示異步處理完成 */ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpResponse httpResponse = exchange.getResponse(); String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress(); // 檢查黑名單 Boolean ipCache = IpBlackCache.IP_CACHE.getIfPresent(ip); if (ipCache != null && ipCache) { //修改code為429,太多請求 httpResponse.setStatusCode(HttpStatus.TOO_MANY_REQUESTS); if (!httpResponse.getHeaders().containsKey("Content-Type")) { httpResponse.getHeaders().add("Content-Type", "application/json"); } Map<String, String> errorInfo = new HashMap<>(); errorInfo.put("code", HttpStatus.TOO_MANY_REQUESTS.toString()); errorInfo.put("msg", "訪問太頻繁"); String httpBody = JSONObject.toJSONString(errorInfo); log.info("該ip:{}已被拉入黑名單,錯誤信息{}", ip, httpBody); return httpResponse.writeWith(Flux.just(exchange.getResponse().bufferFactory().wrap(httpBody.getBytes()))); } // 采用默認令牌桶算法,如果觸發限流,返回HTTP響應狀態碼429 // 若需替換默認算法(如改用漏桶算法),實現RateLimiter接口,重寫isAllowed方法 return chain.filter(exchange).then(Mono.fromRunnable(() -> { // 檢查限流結果,將IP放入黑名單緩存中 if (httpResponse.getStatusCode() == HttpStatus.TOO_MANY_REQUESTS) { IpBlackCache.IP_CACHE.put(ip, true); } })); } /** * 獲取攔截器順序,使用最高級別,第一攔截 */ @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; } }
擴展:自定義的Redis令牌桶限流
@Component public class XxxRedisRateLimiter extends RedisRateLimiter { public Mono<Response> isAllowed(xxx) { xxx } }

3、重試過濾器:
|
一、重試過濾器的優點: |
|
1、容錯性提升:自動處理瞬時故障(如網絡抖動、服務短時不可用)。 2、可用性增強:降低單次調用失敗對核心流程的影響。 3、運維成本降低:減少人工介入,實現自動化恢復。 4、用戶體驗優化:通過后臺重試避免用戶感知到頻繁失敗。 |
|
二、重試機制的核心價值: |
|
1、應對分布式系統的不可靠性:網絡和服務依賴的故障是常態,需容錯機制保障穩定性。 2、解決瞬時故障的普遍性:服務重啟、資源競爭等短暫問題可通過重試快速恢復。 3、緩解依賴服務的波動性:第三方服務或云基礎設施可能存在不穩定性,重試提供緩沖。 4、強化系統魯棒性:在部分故障下維持核心功能,避免整體崩潰。 |
|
三、典型使用場景: |
|
1、HTTP/API調用:處理5xx服務端錯誤或網絡超時。 2、數據庫操作:應對連接超時、死鎖等臨時異常。 3、消息隊列消費:消息處理失敗后重試,確保最終一致性。 4、文件/資源訪問:臨時IO錯誤或資源鎖沖突的場景。 |
|
四、注意事項: |
|
1、避免無限重試:設定最大重試次數,防止雪崩效應。 2、區分錯誤類型:僅對可恢復錯誤(如5xx、超時)重試,非重試錯誤(如4xx)直接失敗。 3、退避策略:采用遞增延遲(如指數退避),緩解下游服務壓力。 4、監控與告警:記錄重試日志,及時發現異常高頻重試模式。 |
(1)、網關配置文件bootstrap-three.yml:
#重試過濾器 # 設置重試次數:最多重試3次。 # 狀態碼系列:當響應的狀態碼屬于SERVER_ERROR系列(即5xx狀態碼)時,會觸發重試。 # 指定狀態碼:當響應的狀態碼為SERVICE_UNAVAILABLE(通常是503狀態碼)時,也會觸發重試 # 對外暴露端口 server: port: 9090 spring: #項目名 application: name: cloud-gateway-service cloud: nacos: config: server-addr: localhost:8848 file-extension: yaml # namespace: 3fd40f6b-0bc9-4a59-8838-0a64269125b4 # context-path: /nacos # username: nacos # password: nacos discovery: server-addr: localhost:8848 # namespace: 3fd40f6b-0bc9-4a59-8838-0a64269125b4 # username: nacos # password: nacos #############################網關配置########################### gateway: # 服務路由配置(路由是構建網關的基本模塊,由ID,目標URI,一系列的斷言和過濾器組成) routes: # 路由的ID,沒有固定規則但要求唯一,建議配合服務名 - id: cloud-provider-service # 路由的地址,lb表示使用負載均衡(引入負載均衡依賴)到微服務,也可以使用http正常轉發 # uri: lb://服務注冊中心注冊的服務名稱 # uri: http://localhost:8080 uri: lb://cloud-provider-service #斷言工廠列表: predicates: - Path=/provider/** filters: # 重試過濾器 - name: Retry args: # 重試次數 retries: 3 # 哪些段的狀態碼需要重試, 默認5xx series: - SERVER_ERROR # 指定哪些狀態需要重試 statuses: SERVICE_UNAVAILABLE - id: cloud-consumer-service uri: lb://cloud-consumer-service predicates: - Path=/consumer/** filters: - name: Retry args: retries: 3 series: - SERVER_ERROR statuses: SERVICE_UNAVAILABLE
(2)、相關測試接口:
/** * 重試過濾器測試 * */ private int requestCount = 0; @GetMapping("/testRetry") public ResponseEntity<String> test() { requestCount++; System.out.println("生產者服務測試請求重試次數: " + requestCount); // 返回503狀態碼 return new ResponseEntity<>("Service Unavailable", HttpStatus.SERVICE_UNAVAILABLE); }

4、請求大小限制過濾器:
當客戶端請求體大小超過 maxSize 設定值時,網關會直接攔截請求,返回 HTTP 413 (Payload Too Large) 狀態碼
(1)、保障系統穩定性:攔截超大請求,防止內存溢出和服務崩潰
(2)、強化安全防護:阻斷DDoS攻擊,避免惡意大流量沖擊后端
(3)、優化網絡性能:降低無效帶寬消耗,提升整體吞吐量
(4)、統一流量治理:標準化異常響應格式,簡化客戶端錯誤處理邏輯
(1)、網關配置文件bootstrap-four.yml:
#請求大小限制過濾器 # 當客戶端請求體大小超過 maxSize 設定值時,網關會直接攔截請求,返回 HTTP 413 (Payload Too Large) 狀態碼。 # 單位換算 maxSize 以字節為單位,計算方式: 1MB = 1024 * 1024 = 1,048,576 bytes # Windows系統文件生成(PowerShell)0.9M文件:fsutil file createnew 0.9M.bin 900000 # Windows系統文件生成(PowerShell)1.1M文件:fsutil file createnew 1.1M.bin 1100000 # 對外暴露端口 server: port: 9090 spring: #項目名 application: name: cloud-gateway-service cloud: nacos: config: server-addr: localhost:8848 file-extension: yaml # namespace: 3fd40f6b-0bc9-4a59-8838-0a64269125b4 # context-path: /nacos # username: nacos # password: nacos discovery: server-addr: localhost:8848 # namespace: 3fd40f6b-0bc9-4a59-8838-0a64269125b4 # username: nacos # password: nacos #############################網關配置########################### gateway: # 服務路由配置(路由是構建網關的基本模塊,由ID,目標URI,一系列的斷言和過濾器組成) routes: # 路由的ID,沒有固定規則但要求唯一,建議配合服務名 - id: cloud-provider-service # 路由的地址,lb表示使用負載均衡(引入負載均衡依賴)到微服務,也可以使用http正常轉發 # uri: lb://服務注冊中心注冊的服務名稱 # uri: http://localhost:8080 uri: lb://cloud-provider-service #斷言工廠列表: predicates: - Path=/provider/** filters: # 請求大小限制過濾器 - name: RequestSize args: # 單位字節:限制1M maxSize: 1000000 - id: cloud-consumer-service uri: lb://cloud-consumer-service predicates: - Path=/consumer/** filters: - name: RequestSize args: maxSize: 1000000
(2)、相關測試接口:
/** * 請求大小限制過濾器測試 * */ @PostMapping("/testRequestSize") public ResponseEntity<String> handleFileUpload(@RequestParam("file") MultipartFile file) { // 網關會先攔截大文件請求,此處只需要處理通過網關的合法請求 return ResponseEntity.ok().body(String.format("文件上傳成功!文件名:%s,大小:%d 字節", file.getOriginalFilename(), file.getSize())); }

浙公網安備 33010602011771號