Spring Cloud Gateway路由+斷言+過濾

目錄

    • 介紹
    • 核心功能
    • 三大核心
    • Route以服務名動態獲取URL
    • Predicate常用斷言
      • Path Route Predicate
      • After Route Predicate
      • Before Route Predicate
      • Between Route Predicate
      • Cookie Route Predicate
      • Header Route Predicate
      • Host Route Predicate
      • Query Route Predicate
      • RemoteAddr Route Predicate
      • Method Route Predicate
    • 自定義Predicate
    • 自定義Filter
      • 自定義全局Filter統計接口調用耗時情況
      • 自定義條件Filter
    • 總結

介紹


Spring Cloud Gateway 是 Spring Cloud 生態系統中的一個基于 Spring WebFlux 的 API 網關解決方案,旨在為微服務架構提供統一的入口點,支持路由、過濾、負載均衡等功能。它通過非阻塞的響應式編程模型,提供了高效、靈活的 API 網關能力。

核心功能


  • 動態路由: 支持基于路徑、Header、Query參數等規則的動態路由。
  • 過濾器鏈: 通過全局過濾器 (Global Filter) 和局部過濾器 (Gateway Filter) 實現請求增強與響應修改。
  • 負載均衡: 集成Spring Cloud LoadBalancer,支持多實例流量分發。
  • 限流與熔斷: 內置限流功能,支持 Redis 令牌桶算法,可結合 Resilience4j 實現熔斷。
  • 安全與監控: 支持JWT、OAuth2等認證機制,保護后端服務。

三大核心


1. 路由 (Route)

路由是網關的核心,用于定義請求的轉發規則。他由ID、目標URL、一系列的斷言和過濾器組成,如果斷言為true則路由匹配成功。一個路由包含以下屬性:

  • ID: 路由的唯一標識。
  • URI: 目標服務的地址,支持 http、lb(負載均衡)等協議。
  • 斷言: 定義路由匹配條件,如路徑、Header、方法等。
  • 過濾器: 對請求或響應進行處理的邏輯。

2. 斷言 (Predicate)

斷言用于判斷請求是否符合路由規則。常見的斷言包括:

  • Path: 路徑匹配。
  • Method: HTTP 方法匹配。
  • Header: 請求頭匹配。
  • Query: 請求參數匹配。
  • After、Before、Between: 時間范圍匹配。

3. 過濾 (Filter)

過濾器用于在請求轉發前或響應返回后執行特定邏輯。常見的過濾器包括:

  • 全局過濾器: 對所有路由生效,如日志記錄、認證校驗。
  • 局部過濾器: 僅對特定路由生效,如路徑重寫、請求限流。

Route以服務名動態獲取URL


網關服務 cloud-gateway9527 引入依賴

<!-- gateway -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 服務注冊發現consul discovery,網關也要注冊進服務注冊中心統一管控 -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId><exclusions><exclusion><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId></exclusion></exclusions>
</dependency>
<!-- 指標監控健康檢查的actuator -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- lombok -->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>

yml配置

server:port: 9527spring:application:name: cloud-gateway# Spring Cloud Consul for Service Discoverycloud:consul:host: localhostport: 8500discovery:service-name: ${spring.application.name}gateway:routes:- id: pay_routh1  # pay_routh1 (路由的ID,沒有固定規則但要求唯一,建議配合服務名)uri: lb://cloud-payment-service  # 服務名predicates:- Path=/pay/gateway/get/**  # 斷言,路徑匹配的進行路由

訂單服務 cloud-feign-order9002:OrderGatewayController

@RestController
public class OrderGatewayController {@Resourceprivate PayFeignApi payFeignApi;@GetMapping("/feign/pay/gateway/get/{id}")public Result getById(@PathVariable("id") Integer id) {return payFeignApi.getById(id);}
}

Feign接口 cloud-common-api:PayFeignApi

@FeignClient("cloud-gateway")
public interface PayFeignApi {@GetMapping("/pay/gateway/get/{id}")public Result getById(@PathVariable("id") Integer id);
}

支付服務 cloud-payment8001:PayGatewayController

@RestController
public class PayGatewayController {@Resourceprivate PayService payService;@GetMapping(value = "/pay/gateway/get/{id}")public Result<Pay> getById(@PathVariable("id") Integer id) {Pay pay = payService.getById(id);return Result.success(pay);}
}

測試結果

啟動支付服務8001,啟動訂單服務9002,訪問 http://localhost:9002/feign/pay/gateway/get/1 返回異常。再啟動網關服務9527,訪問 http://localhost:9002/feign/pay/gateway/get/1 返回成功。

Predicate常用斷言


Path Route Predicate

spring:cloud:gateway:routes:- id: pay_routh1  # pay_routh1 (路由的ID,沒有固定規則但要求唯一,建議配合服務名)uri: lb://cloud-payment-service  # 服務名predicates:- Path=/pay/gateway/get/**  # 斷言,路徑匹配的進行路由

測試結果

訪問 http://localhost:9527/pay/gateway/get/1 返回成功。

After Route Predicate

# 獲取當前時間串
ZonedDateTime now = ZonedDateTime.now();
System.out.println(now);
spring:cloud:gateway:routes:- id: pay_routh1  # pay_routh1 (路由的ID,沒有固定規則但要求唯一,建議配合服務名)uri: lb://cloud-payment-service  # 服務名predicates:- Path=/pay/gateway/get/**  # 斷言,路徑匹配的進行路由- After=2025-04-19T15:51:15.516781+08:00[Asia/Shanghai]  # 在某個時間之后可以訪問

測試結果

2025-04-19 15:51:15 之前訪問 http://localhost:9527/pay/gateway/get/1 返回失敗。
2025-04-19 15:51:15 之后訪問 http://localhost:9527/pay/gateway/get/1 返回成功。

Before Route Predicate

spring:cloud:gateway:routes:- id: pay_routh1  # pay_routh1 (路由的ID,沒有固定規則但要求唯一,建議配合服務名)uri: lb://cloud-payment-service  # 服務名predicates:- Path=/pay/gateway/get/**  # 斷言,路徑匹配的進行路由- Before=2025-04-19T15:51:15.516781+08:00[Asia/Shanghai]  # 在某個時間之前可以訪問

測試結果

2025-04-19 15:51:15 之前訪問 http://localhost:9527/pay/gateway/get/1 返回成功。
2025-04-19 15:51:15 之后訪問 http://localhost:9527/pay/gateway/get/1 返回失敗。

Between Route Predicate

spring:cloud:gateway:routes:- id: pay_routh1  # pay_routh1 (路由的ID,沒有固定規則但要求唯一,建議配合服務名)uri: lb://cloud-payment-service  # 服務名predicates:- Path=/pay/gateway/get/**  # 斷言,路徑匹配的進行路由- Between=2025-04-19T16:11:15.516781+08:00[Asia/Shanghai],2025-04-19T16:12:15.516781+08:00[Asia/Shanghai]  # 在某個時間段之間可以訪問

測試結果

2025-04-19 16:11:15 到 2025-04-19 16:12:15 時間段之間訪問 http://localhost:9527/pay/gateway/get/1 返回成功。

Cookie Route Predicate

spring:cloud:gateway:routes:- id: pay_routh1  # pay_routh1 (路由的ID,沒有固定規則但要求唯一,建議配合服務名)uri: lb://cloud-payment-service  # 服務名predicates:- Path=/pay/gateway/get/**  # 斷言,路徑匹配的進行路由- Cookie=username,zzyy  # cookie中含有username=zzyy可以訪問

測試結果

  • 原生命令測試
    curl http://localhost:9527/pay/gateway/get/1 --cookie “username=zzyy” 返回成功。
  • postman測試
    請求頭中添加 cookie:username=zzyy,訪問 http://localhost:9527/pay/gateway/get/1 返回成功。

Header Route Predicate

spring:cloud:gateway:routes:- id: pay_routh1  # pay_routh1 (路由的ID,沒有固定規則但要求唯一,建議配合服務名)uri: lb://cloud-payment-service  # 服務名predicates:- Path=/pay/gateway/get/**  # 斷言,路徑匹配的進行路由- Header=X-Request-Id,\d+  # 請求頭中含有X-Request-Id且值為整數的正則表達式可以訪問

測試結果

  • 原生命令測試
    curl http://localhost:9527/pay/gateway/get/1 -H “X-Request-Id:123” 返回成功。
  • postman測試
    請求頭中添加 X-Request-Id:123,訪問 http://localhost:9527/pay/gateway/get/1 返回成功。

Host Route Predicate

spring:cloud:gateway:routes:- id: pay_routh1  # pay_routh1 (路由的ID,沒有固定規則但要求唯一,建議配合服務名)uri: lb://cloud-payment-service  # 服務名predicates:- Path=/pay/gateway/get/**  # 斷言,路徑匹配的進行路由- Host=**.zzyy.com  # 主機地址后必須含有.zzyy.com可以訪問

測試結果

  • 原生命令測試
    curl http://localhost:9527/pay/gateway/get/1 -H “Host:www.zzyy.com” 返回成功。
  • postman測試
    請求頭中添加 Host:www.zzyy.com,訪問 http://localhost:9527/pay/gateway/get/1 返回成功。

Query Route Predicate

spring:cloud:gateway:routes:- id: pay_routh1  # pay_routh1 (路由的ID,沒有固定規則但要求唯一,建議配合服務名)uri: lb://cloud-payment-service  # 服務名predicates:- Path=/pay/gateway/get/**  # 斷言,路徑匹配的進行路由- Query=uid,\d+  # 請求參數必須含有uid且值為整數的正則表達式可以訪問

測試結果

訪問 http://localhost:9527/pay/gateway/get/1?uid=123 返回成功。

RemoteAddr Route Predicate

spring:cloud:gateway:routes:- id: pay_routh1  # pay_routh1 (路由的ID,沒有固定規則但要求唯一,建議配合服務名)uri: lb://cloud-payment-service  # 服務名predicates:- Path=/pay/gateway/get/**  # 斷言,路徑匹配的進行路由- RemoteAddr=192.168.42.1/24  # 遠程訪問地址必須是192.168.42.xx才能訪問

測試結果

當前電腦IP為 192.168.42.3,訪問 http://192.168.42.3:9527/pay/gateway/get/1 返回成功。

Method Route Predicate

spring:cloud:gateway:routes:- id: pay_routh1  # pay_routh1 (路由的ID,沒有固定規則但要求唯一,建議配合服務名)uri: lb://cloud-payment-service  # 服務名predicates:- Path=/pay/gateway/get/**  # 斷言,路徑匹配的進行路由- Method=GET,POST  # get/post請求可以訪問

測試結果

get 請求訪問 http://localhost:9527/pay/gateway/get/1 返回成功。

自定義Predicate


網關服務 cloud-gateway9527 中新建 MyRoutePredicateFactory

// 自定義配置會員等級,按照 鉑、金、銀和yml配置的會員等級,才可以訪問
// 繼承 AbstractRoutePredicateFactory
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {// 無參構造方法public MyRoutePredicateFactory() {super(MyRoutePredicateFactory.Config.class);}// 短格式public List<String> shortcutFieldOrder() {return Collections.singletonList("userType");}// 重寫apply方法@Overridepublic Predicate<ServerWebExchange> apply(Config config) {return new Predicate<ServerWebExchange>() {@Overridepublic boolean test(ServerWebExchange serverWebExchange) {// 檢查request參數中是否存在userType,且值和config中的相同,則可以訪問String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");return userType != null && userType.equals(config.getUserType());}};}// 這個Config類就是路由斷言規則public static class Config {private @NotNull String userType;  // 鉑、金、銀和yml配置的會員等級public Config() {}public String getUserType() {return userType;}public void setUserType(String userType) {this.userType = userType;}}
}

yml配置

server:port: 9527spring:application:name: cloud-gateway# Spring Cloud Consul for Service Discoverycloud:consul:host: localhostport: 8500discovery:service-name: ${spring.application.name}gateway:routes:- id: pay_routh1  # pay_routh1 (路由的ID,沒有固定規則但要求唯一,建議配合服務名)uri: lb://cloud-payment-service  # 服務名predicates:- Path=/pay/gateway/get/**  # 斷言,路徑匹配的進行路由- My=gold  # 自定義斷言

測試結果

訪問 http://localhost:9527/pay/gateway/get/1?userType=gold 返回成功。

自定義Filter


自定義全局Filter統計接口調用耗時情況

網關服務 cloud-gateway9527 中新建 MyGlobalFilter

@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered {private static final String START_TIME = "start_time";  // 開始調用方法的時間@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 記錄開始時間exchange.getAttributes().put(START_TIME, System.currentTimeMillis());return chain.filter(exchange).then(Mono.fromRunnable(() -> {Long startTime = exchange.getAttribute(START_TIME);if (startTime != null) {URI uri = exchange.getRequest().getURI();log.info("訪問接口主機:" + uri.getHost() + ",端口:" + uri.getPort() +",URL:" + uri.getPath() + ",參數:" + uri.getRawQuery() +",時長:" + (System.currentTimeMillis() - startTime) + "毫秒");}}));}// 值越小,優先級越高@Overridepublic int getOrder() {return 0;}
}

測試結果

訪問 http://localhost:9527/pay/gateway/get/1 日志輸出:訪問接口主機:localhost,端口:9527,URL:/pay/gateway/get/1,參數:null,時長:6毫秒

自定義條件Filter

// 繼承 AbstractGatewayFilterFactory
@Component
@Slf4j
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config>  {// 無參構造方法public MyGatewayFilterFactory() {super(MyGatewayFilterFactory.Config.class);}// 短格式public List<String> shortcutFieldOrder() {return Arrays.asList("state");}// 重寫apply方法@Overridepublic GatewayFilter apply(MyGatewayFilterFactory.Config config) {return new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();log.info("進入自定義條件過濾器MyGatewayFilterFactory, state=" + config.getState());if (request.getQueryParams().containsKey("zzyy")) {return chain.filter(exchange);}exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);return exchange.getResponse().setComplete();}};}public static class Config {private String state;public Config() {}public String getState() {return state;}public void setState(String state) {this.state = state;}}
}

yml配置

server:port: 9527spring:application:name: cloud-gateway# Spring Cloud Consul for Service Discoverycloud:consul:host: localhostport: 8500discovery:service-name: ${spring.application.name}gateway:routes:- id: pay_routh1  # pay_routh1 (路由的ID,沒有固定規則但要求唯一,建議配合服務名)uri: lb://cloud-payment-service  # 服務名predicates:- Path=/pay/gateway/get/**  # 斷言,路徑匹配的進行路由filters:- My=zzyy  # 自定義條件過濾器

測試結果

訪問 http://localhost:9527/pay/gateway/get/1?zzyy=16 返回成功。

總結


以上主要介紹了 Spring Cloud Gateway 路由、斷言、過濾的相關知識,以及自定義 Predicate 和 Filter,想了解更多 Spring Cloud Gateway 知識的小伙伴請參考 Spring Cloud Gateway 官網 進行學習,學習更多 Spring Cloud 實戰實用技巧的小伙伴,請關注后期發布的文章,認真看完一定能讓你有所收獲。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/78880.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/78880.shtml
英文地址,請注明出處:http://en.pswp.cn/web/78880.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

springboot集成langchain4j記憶對話

流式輸出 LLM 一次生成一個標記&#xff08;token&#xff09;&#xff0c;因此許多 LLM 提供商提供了一種方式&#xff0c;可以逐個標記地流式傳輸響應&#xff0c;而不是等待整個文本生成完畢。 這顯著改善了用戶體驗&#xff0c;因為用戶不需要等待未知的時間&#xff0c;幾…

【SpringCloud GateWay】Connection prematurely closed BEFORE response 報錯分析與解決方案

一、背景 今天業務方調用我們的網關服務報錯: Connection prematurely closed BEFORE response二、原因分析 三、解決方案 第一步: 增加 SCG 服務的JVM啟動參數,調整連接獲取策略。 將連接池獲取策略由默認的 FIFO&#xff08;先進先出&#xff09;變更為 LIFO&#xff08…

使用ZYNQ芯片和LVGL框架實現用戶高刷新UI設計系列教程(第十一講)

這一期講解lvgl中下拉框的基礎使用&#xff0c;下拉列表允許用戶從選項列表中選擇一個值&#xff0c;下拉列表的選項表默認是關閉的&#xff0c;其中的選項可以是單個值或預定義文本。 當單擊下拉列表后&#xff0c;其將創建一個列表&#xff0c;用戶可以從中選擇一個選項。 當…

【神經網絡與深度學習】VAE 在解碼前進行重參數化

在 VAE 中&#xff0c;解碼之前進行重參數化主要有以下幾個重要原因&#xff1a; 可微分性 在深度學習里&#xff0c;模型是通過反向傳播算法來學習的&#xff0c;而這需要計算梯度。若直接從潛在變量的分布 (q_{\theta}(z|x))&#xff08;由編碼器輸出的均值 (\mu) 和方差 (…

BBDM學習筆記

1. configs 1.1 LBBDM: Latent BBDM [readme]

mysql主從復制搭建,并基于?Keepalived + VIP實現高可用

以下是基于 ?Keepalived VIP? 實現 MySQL 主從復制高可用的詳細步驟&#xff0c;涵蓋主從復制搭建與故障自動切換&#xff1a; 一、MySQL 主從復制搭建&#xff08;基礎步驟回顧&#xff09; 1. ?主庫&#xff08;Master&#xff09;配置? 修改配置文件? /etc/my.cnf&…

CD36.【C++ Dev】STL庫的string的使用 (下)

目錄 1.reserve函數(不是reverse) 代碼示例 2.resize 代碼示例 3.reserve和resize的區別 4.shrink_to_fit 代碼示例 5.與C語言的配合的接口函數: c_str 代碼示例 6.rfind 知識回顧:find函數 rfind 代碼示例 練習題: 字符串最后一個單詞的長度 代碼 提交結果 ?…

STM32的網絡天氣時鐘項目

一、項目概述與硬件架構 1.1 核心功能 本智能天氣時鐘系統集成了實時天氣獲取、網絡時間同步、環境監測和低功耗管理四大核心功能&#xff1a; 網絡數據獲取&#xff1a; 通過ESP8266 WiFi模塊連接心知天氣API&#xff08;每小時更新&#xff09;獲取北京標準時間服務器的時…

FPGA DDR4多通道管理控制器設計

DDR4控制器一般采用自帶的MIG控制器&#xff0c;用戶控制主要是基于MIG IP核進行設計 實際工程項目中可能只掛載了一組DDR&#xff0c;但是用戶數據可能有很多種&#xff0c;用戶通過給每種數據劃分特定地址進行存儲&#xff0c;如何實現靈活管理成為設計的關鍵 為了方便后端數…

低代碼 x AI,解鎖數智化應用的創新引擎

AI 智能體開發指南 隨著全球信息化浪潮的持續推進&#xff0c;數字化、智能化轉型已成為企業發展的必經之路。在這個變革的時代&#xff0c;企業面臨著前所未有的挑戰與機遇。一方面&#xff0c;市場環境瞬息萬變&#xff0c;企業需要快速響應并調整業務模式&#xff1b;另一方…

【Spring Boot 注解】@Configuration與@AutoConfiguration

文章目錄 Configuration與AutoConfiguration一、Configuration二、AutoConfiguration Configuration與AutoConfiguration 一、Configuration 這是最常用的 Spring 注解之一&#xff0c;表示當前類是一個 配置類&#xff0c;可以定義 Bean 方法&#xff0c;等效于傳統的 XML 配…

arXiv論文 MALOnt: An Ontology for Malware Threat Intelligence

文章講惡意軟件威脅情報本體。 作者信息 作者是老美的&#xff0c;單位是倫斯勒理工學院&#xff0c;文章是2020年的預印本&#xff0c;不知道后來發表在哪里&#xff08;沒搜到&#xff0c;或許作者懶得投稿&#xff0c;也可能是改了標題&#xff09;。 中心思想 介紹開源…

【存儲管理—動態不等長存儲資源分配算法】

文章目錄 一、實驗目的二、實驗內容與設計思想實驗內容設計思路 三、實驗代碼實現四、總結 一、實驗目的 理解動態異長存儲分區資源管理&#xff0c;掌握所需數據結構和管理程序&#xff0c;了解各種存儲分配算法的優點和缺點。 二、實驗內容與設計思想 實驗內容 1.分析uni…

快速上手 Docker:從入門到安裝的簡易指南(Mac、Windows、Ubuntu)

PS&#xff1a;筆者在五一剛回來一直搞Docker部署AI項目&#xff0c;發現從開發環境遷移到生成環境時&#xff0c;Docker非常好用。但真的有一定上手難度&#xff0c;推薦讀者多自己嘗試踩踩坑。 本篇幅有限&#xff0c;使用與修改另起篇幅。 一、Docker是什么 #1. Docker是什…

LabVIEW高沖擊加速度校準系統

在國防科技領域&#xff0c;高 g 值加速度傳感器廣泛應用于先進兵器研制&#xff0c;如深侵徹系統、精確打擊彈藥及鉆地彈藥等。其性能指標直接影響研究結果的準確性與可靠性&#xff0c;因此對該傳感器進行定期校準意義重大。高沖擊加速度校準系統具備多方面功能&#xff0c;適…

FPGA 純邏輯NVME raid0 IP核

系統采用XCZU19EG搭載4個三星990 PRO SSD 單盤讀寫不低于3GB/s 4盤總帶寬不低于12GB/s

GStreamer開發筆記(三):測試gstreamer/v4l2+sdl2/v4l2+QtOpengl打攝像頭延遲和內存

若該文為原創文章&#xff0c;轉載請注明原文出處 本文章博客地址&#xff1a;https://blog.csdn.net/qq21497936/article/details/147714800 長沙紅胖子Qt&#xff08;長沙創微智科&#xff09;博文大全&#xff1a;開發技術集合&#xff08;包含Qt實用技術、樹莓派、三維、O…

CATIA高效工作指南——零件建模篇(二)

一、PowerCopy特征復用技術 1.1 智能特征封裝 通過??幾何圖形集(Geometrical Set)??構建參數化特征組&#xff0c;將關聯的草圖、曲面、實體等元素進行邏輯封裝。操作流程如下&#xff1a; 創建新幾何圖形集并完成特征建模激活PowerCopy命令&#xff0c;選擇目標幾何集定…

CentOS 7 安裝OpenJDK 17 JRE

CentOS 7 自帶的java 版本為&#xff1a;java version "1.8.0_311"&#xff0c; 有些軟件的運行需要更高的java版本。CentOS 7 自帶的默認倉庫里 沒有 OpenJDK 17&#xff0c;但是 Adoptium 項目&#xff08;前身 AdoptOpenJDK&#xff09;提供了穩定的 OpenJDK 17 版…

【c++】 我的世界

太久沒更新小游戲了 給個贊和收藏吧&#xff0c;求求了 要游戲的請私聊我 #include <iostream> #include <vector>// 定義世界大小 const int WORLD_WIDTH 20; const int WORLD_HEIGHT 10;// 定義方塊類型 enum BlockType {AIR,GRASS,DIRT,STONE };// 定義世界…