簡述
不同的微服務一般會有不同的服務地址,客戶端在訪問這些地址的時候需要記錄幾十甚至幾百個地址,這對於客戶端來說過於復雜和難以維護。

這樣存在的問題有:客戶端會請求多個不同的服務,需要維護不同的請求地址,增加開發難度。而且這樣的機制會增加身份認證的難度,每個微服務需要獨立認證。
微服務網關
微服務網關就應運而生,微服務網關介於客戶端與服務器之間的中間層,它是一個服務器,是系統對外的唯一入口。所有的外部請求都會先經過微服務網關。客戶端只需要與網關交互,只知道一個網關地址即可。

Zuul網關
Zuul網關是是Netflflix開源的微服務網關,它可以和Eureka、Ribbon、Hystrix等組件配合使用,Zuul組件的核心是一系列的過濾器。這些過濾器可以完成:
動態路由:動態將請求路由到不同后端集群
壓力測試:逐漸增加指向集群的流量,以了解性能
負載分配:為每一種負載類型分配對應容量,並棄用超出限定值的請求
靜態響應處理:邊緣位置進行響應,避免轉發到內部集群
身份認證和安全: 識別每一個資源的驗證要求,並拒絕那些不符的請求。Spring Cloud對Zuul進行了整合和增強。
zuul的底層基於Servlet,本質上就是一系列的filter過濾器。
zuul的基本使用
首先要清楚的是zuul是一台服務器,我們要在項目中創建一個新的模組

引入zuul的相關依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency>
在springboot啟動類上加入zuul的支持注解

至此zuul的准備工作已經完成
zuul基礎路由配置
這里對路由的理解就是根據請求URL,將請求分配到對應的處理程序。在微服務體系中,Zuul負責接收所有的請求。根據不同的URL匹配規則,將不同的請求轉發到不同的微服務處理。
我們在項目的yml文件中可以配置zuul的路由:
#路由配置
zuul:
routes:
product-server: #路由的id
path: /product-service/** #配置映射路徑
url: http://127.0.0.1:9001 #映射路徑的實際微服務url地址
面向服務的路由配置
微服務一般是由幾十、上百個服務組成,對於一個URL請求,最終會確認一個服務實例進行處理。如果對每個服務實例手動指定一個唯一訪問地址,然后根據URL去手動實現請求匹配,這樣做顯然就不合理。
我們首先要添加eureka的依賴:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
然后開啟eureka的服務發現:

我們還需要配置eureka
eureka:
client:
serviceUrl:
defaultZone: http://localhost:9000/eureka/
registry-fetch-interval-seconds: 5 # 獲取服務列表的周期:5s
instance:
preferIpAddress: true
ip-address: 127.0.0.1
此時我們的zuul基礎路由配置中的url就可以不用寫了,因為此時的服務地址是從eureka中獲取的
我們只需配置serviceId即可
zuul:
routes:
product-service: # 這里是路由id,隨意寫
path: /product-service/** # 這里是映射路徑
# url: http://127.0.0.1:9001 # 映射路徑對應的實際url地址
serviceId: service-product #整合eureka后會從eureka中獲取服務地址
sensitiveHeaders: #默認zuul會屏蔽cookie,cookie不會傳到下游服務,這里設置為空則取 消默認的黑名單,如果設置了具體的頭信息則不會傳到下游服務
配置的簡化
如果路由的id和service的id一致的話,我們可以只寫這么一行配置映射路徑
zuul:
routes:
#product-service: # 這里是路由id,隨意寫
# path: /product-service/** # 這里是映射路徑
# # url: http://127.0.0.1:9001 # 映射路徑對應的實際url地址
# serviceId: service-product #整合eureka后會從eureka中獲取服務地址
# sensitiveHeaders: #默認zuul會屏蔽cookie,cookie不會傳到下游服務,這里設置為空則取 消默認的黑名單,如果設置了具體的頭信息則不會傳到下游服務
service-product: /product-service/**
Zuul網關加入之后的架構圖

Zuul網關過濾器
zuul的路由功能實現了統一處理外部請求的功能,負責將外部請求轉發到具體的微服務實例上,是實現外部訪問統一入口的基礎。
zuul還提供過濾器功能,負責對請求的處理過程進行干預,是實現請求校驗、服務聚合等功能的基礎。
ZuulFilter有四種類型:
|
PRE
|
這種過濾器在請求被路由之前調用。我們可利用這種過濾器實現身份驗證、在集群中選擇請
求的微服務、記錄調試信息等。
|
|
ROUTING
|
這種過濾器將請求路由到微服務。這種過濾器用於構建發送給微服務的請求,並使用
Apache HttpClient或Netfifilx Ribbon請求微服務。
|
|
POST
|
這種過濾器在路由到微服務以后執行。這種過濾器可用來為響應添加標准的HTTP
Header、收集統計信息和指標、將響應從微服務發送給客戶端等。
|
|
ERROR
|
在其他階段發生錯誤時執行該過濾器。
|
package hjj.filter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import org.apache.http.HttpStatus; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; /** * 自定義的zuul過濾器 */ @Component public class LoginFilter extends ZuulFilter { //定義過濾器類型 pre routing post error @Override public String filterType() { return "pre"; } //指定過濾器的執行順序 返回值越小執行順序越高 @Override public int filterOrder() { return 1; } //當前過濾器是否生效 true使用 false不使用 @Override public boolean shouldFilter() { return true; } //執行過濾器中的業務邏輯 身份認證,所有的請求都需要攜帶一個參數:access-token @Override public Object run() throws ZuulException { //獲取上下文對象 RequestContext ctx = RequestContext.getCurrentContext(); //獲取request請求 HttpServletRequest request = ctx.getRequest(); //獲取request參數 String token = request.getParameter("access-token"); //獲取token並進行判斷 if(token == null){ //攔截請求,認證失敗 ctx.setSendZuulResponse(false);//攔截請求 ctx.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);//返回錯誤碼 } System.out.println("執行了過濾器"); return null; } }
