## 概述 Spring Cloud Zuul 是 Spring Cloud Netflix 子項目的核心組件之一,可以作為微服務架構中的 API 網關使用,有以下用途: - 鑒權:對於訪問每個服務的請求進行鑒權,拒絕鑒權失敗的請求 - 監控:對系統的請求進行監控,記錄請求響應日誌,實時統計當前系統 ...
概述
Spring Cloud Zuul 是 Spring Cloud Netflix 子項目的核心組件之一,可以作為微服務架構中的 API 網關使用,有以下用途:
- 鑒權:對於訪問每個服務的請求進行鑒權,拒絕鑒權失敗的請求
- 監控:對系統的請求進行監控,記錄請求響應日誌,實時統計當前系統的訪問量以及監控狀態
- 壓力測試:幫助對集群進行可控的壓力測試
- 灰度測試:灰度發佈可以保證整體系統的穩定,在初始灰度時就可以發現問題併進行調整
- 動態路由:基於請求路徑,將請求分發到指定的客戶端
- 負載控制:統一控制客戶端請求壓力,超過壓力的請求直接拒絕
- 靜態響應處理:在邊緣位置直接建立部分響應,避免其流入內部集群
構建 Zuul 網關
創建 zuul-service 項目,引入依賴,本項目基於 SpringBoot 2.3.1,SpringCloud Hoxton.SR12
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
在 application.yml 配置文件中添加如下配置:
server:
port: 9080 # 指定運行埠
spring:
application:
name: zuul-service # 指定服務名稱
zuul:
routes:
blog:
path: /baidu/**
url: https://www.baidu.com # url用於配置符合path的請求路徑路由到的服務地址
在啟動類中添加 @EnableZuulProxy
註解
@EnableZuulProxy
@SpringBootApplication
public class ZuulServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulServiceApplication.class, args);
}
}
Spring Cloud Netflix Zuul 提供了許多過濾器,具體取決於啟用的 Zuul 的註解,@EnableZuulProxy
是 @EnableZuulServer
的超集,包含 @EnableZuulServer
安裝的所有過濾器
啟動項目,在瀏覽器中輸入訪問地址 http://localhost:9080/baidu
,發現請求被路由到百度界面,Zuul 服務搭建成功
Zuul 路由配置
上一節,我們使用路徑的方式匹配路由規則,path 的結構如下
# 其中customName 為用戶自定義名稱
zuul:
routes:
customName:
# 可使用的通配符有以下幾種:
# ?:單個字元
# *:任意多個字元,不包含多級路徑
# **:任意多個字元,包含多級路徑
path: xxx
對於 url 路徑匹配,還可以使用服務名稱匹配
zuul:
routes:
# users為用戶自定義名稱
users:
path: /users/**
# serviceId用於配置符合path的請求路徑路由到的服務名稱
serviceId: users-service
服務名稱匹配也可以使用簡化的配置
zuul:
routes:
service-provider:
path: /users/**
如果只配置 path 不配置 serviceld,則 customName 相當於服務名稱,即 service-provider 會被當作服務名稱,使用 serviceId 要將 zuul 服務註冊到註冊中心使用,比如 Eureka,從而拉取註冊服務列表名稱完成調用
如果想排查配置,可以使用 ignored-services
zuul:
ignoredServices: "*"
routes:
users:
path: /users/**
ignored-services 可以配置不被 zuul 管理的服務列表,多個服務名稱使用號分隔,配置的的務將不被 Zuul代理,在上面的實例中,除了用戶服務外,所有的服務均被忽略
可以通過 zuul.prefix
配置路由首碼,例如:
zuul:
prefix: /api
routes:
users:
path: /users/**
配置請求路徑首碼,所有基於此首碼的請求都由 Zuul 網關提供代理
Zuul 過濾器
Zuul 定義過濾器用來過濾代理請求,提供額外功能邏輯,如許可權驗證、日誌記錄等,filter 與 filter 之間不直接通信,在請求線程中會通過 RequestContext 來共用狀態,它內部是用 ThreadLocal 實現的
Zuul 過濾器分為前置過濾、路由後過濾、後置過濾以及異常過濾:
- 前置過濾:在請求進入 Zuul 後,立刻執行的過濾邏輯
- 路由後過濾:在請求進入 Zuul 後,Zuul 實現請求路由,併在遠程服務調用之前執行過濾邏輯
- 後置過濾:遠程服務調用結束後執行過濾邏輯
- 異常過濾:任意一個過濾器發生異常或遠程服務調用無結果反饋時(調用超時)執行過濾邏輯
ZuulFilter 類及其父類 IZuulFilter 共提供了四種抽象方法:
- filterType:返回字元串數據,代表當前過濾器的類型,可選值有:
- pre:前置過濾器,在請求被路由前執行,通常用於處理身份認證、日誌記錄等
- route:在路由執行後,服務調用前被調用
- error:任意一個 filter 發生異常或遠程服務調用沒有反饋時執行(超時),通常用於處理異
常 - post:在 route 或 error 執行後被調用,一般用於收集服務信息、統計服務性能指標等,也可以對 response 結果做特殊處理
- filterOrder:返回 int 數據,用於為同一種 filterType 的多個過濾器定製執行順序,返回值越小,執行順序越優先
- shouldFilter:返回 boolean 數據,代表當前 filter 是否生效
- run:具體的過濾執行邏輯
具體實例如下:
public class tokenFilter extends ZuulFilter {
@Override
public String filterType() {
//定義過濾器的類型,pre 表示在請求被路由前執行
return "pre";
}
@Override
public int filterOrder() {
//返回int 數據,用於為同一種 filterType 的多個過濾器定製執行順序
//返回值越小,執行順序越優先
return 0;
}
@Override
public boolean shouldFilter() {
//判斷過濾器是否生效,true 代表生效
return true;
}
@Override
public Object run() throws ZuulException {
//獲取上下文
RequestContext currentContext = RequestContext.getCurrentContext();
//獲取 request 對象
HttpServletRequest request = currentContext.getRequest();
//從請求頭獲取 token 的參數
String userToken = request.getParameter("token");
if (StringUtils.isEmpty(userToken)) {
//返回錯誤提示
//false:表示不會繼續往下執行,不會調用服務介面,直接響應給客戶
currentContext.setSendZuulResponse(false);
currentContext.setResponseBody("token is null");
currentContext.setResponseStatusCode(401);
return null;
}
//否則正常執行,調用服務介面...
return null;
}
}