什麼是zuul?(先簡單劇透一下 Zuul=代理+路由+過濾)
它包含了對請求的路由和過濾兩個功能,其中路由功能負責将外部請求轉發到具體的微服務執行個體上,是實作外部通路統一入口的基礎;而過濾器功能則負責對請求的處理過程進行幹預,是實作請求校驗、服務聚合等功能的基礎。
然而實際上,路由功能在真正運作時,它的路由映射和請求轉發都是由幾個不同的過濾器完成的。其中,路由映射主要通過pre類型的過濾器完成,它将請求路徑與配置的路由規則進行比對,以找到需要轉發的目标位址;而請求轉發的部分則是由route類型的過濾器來完成,對pre類型過濾器獲得的路由位址進行轉發。
是以,過濾器可以說是Zuul實作API網關功能最為核心的部件,每一個進入Zuul的HTTP請求都會經過一系列的過濾器處理鍊得到請求響應并傳回給用戶端。
- zuul 是netflix開源的一個API Gateway 伺服器, 本質上是一個web servlet應用。
- Zuul 在雲平台上提供動态路由,監控,彈性,安全等邊緣服務的架構。Zuul 相當于是裝置和 Netflix 流應用的 Web 網站後端所有請求的前門。
- zuul的例子可以Chat快問 new 參考 netflix 在github上的 simple webapp,可以按照netflix 在github wiki 上文檔說明來進行使用。
二、zuul的工作原理
1、過濾器機制
zuul的核心是一系列的filters, 其作用可以類比Servlet架構的Filter,或者AOP。
zuul把Request route到 使用者處理邏輯 的過程中,這些filter參與一些過濾處理,比如Authentication,Load Shedding等。
Zuul提供了一個架構,可以對過濾器進行動态的加載,編譯,運作。
Zuul的過濾器之間沒有直接的互相通信,他們之間通過一個RequestContext的靜态類來進行資料傳遞的。RequestContext類中有ThreadLocal變量來記錄每個Request所需要傳遞的資料。
Zuul的過濾器是由Groovy寫成,這些過濾器檔案被放在Zuul Server上的特定目錄下面,Zuul會定期輪詢這些目錄,修改過的過濾器會動态的加載到Zuul Server中以便過濾請求使用。
下面有幾種标準的過濾器類型:
Zuul大部分功能都是通過過濾器來實作的。Zuul中定義了四種标準過濾器類型,這些過濾器類型對應于請求的典型生命周期。
(1) PRE:這種過濾器在請求被路由之前調用。我們可利用這種過濾器實作身份驗證、在叢集中選擇請求的微服務、記錄調試資訊等。
(2) ROUTING:這種過濾器将請求路由到微服務。這種過濾器用于建構發送給微服務的請求,并使用Apache HttpClient或Netfilx Ribbon請求微服務。
(3) POST:這種過濾器在路由到微服務以後執行。這種過濾器可用來為響應添加标準的HTTP Header、收集統計資訊和名額、将響應從微服務發送給用戶端等。
(4) ERROR:在其他階段發生錯誤時執行該過濾器。
内置的特殊過濾器
zuul還提供了一類特殊的過濾器,分别為:StaticResponseFilter和SurgicalDebugFilter
StaticResponseFilter:StaticResponseFilter允許從Zuul本身生成響應,而不是将請求轉發到源。
SurgicalDebugFilter:SurgicalDebugFilter允許将特定請求路由到分隔的調試叢集或主機。
自定義的過濾器
除了預設的過濾器類型,Zuul還允許我們建立自定義的過濾器類型。
例如,我們可以定制一種STATIC類型的過濾器,直接在Zuul中生成響應,而不将請求轉發到後端的微服務。
2、過濾器的生命周期
Zuul請求的生命周期如圖,該圖較長的描述了各種類型的過濾器的執行順序。
編寫一個類繼承ZuulFilter.java,
package com.fei.springcloud.filter;
import com.netflix.zuul.ZuulFilter;
public class TestFilter extends ZuulFilter{
@Override
public boolean shouldFilter() {
return false;
}
@Override
public Object run() {
return null;
}
@Override
public String filterType() {
return null;
}
@Override
public int filterOrder() {
return 0;
}
}
它們各自的含義與功能總結如下:
- filterType:該函數需要傳回一個字元串來代表過濾器的類型,而這個類型就是在HTTP請求過程中定義的各個階段。在Zuul中預設定義了四種不同生命周期的過濾器類型,具體如下:
- pre:可以在請求被路由之前調用。
- routing:在路由請求時候被調用。
- post:在routing和error過濾器之後被調用。
- error:處理請求時發生錯誤時被調用。
- filterOrder:通過int值來定義過濾器的執行順序,數值越小優先級越高。
- shouldFilter:傳回一個boolean類型來判斷該過濾器是否要執行。我們可以通過此方法來指定過濾器的有效範圍。
- run:過濾器的具體邏輯。在該函數中,我們可以實作自定義的過濾邏輯,來确定是否要攔截目前的請求,不對其進行後續的路由,或是在請求路由傳回結果之後,對處理結果做一些加工等。
從上圖中,我們可以看到,當外部HTTP請求到達API網關服務的時候,首先它會進入第一個階段pre,在這裡它會被pre類型的過濾器進行處理,該類型的過濾器主要目的是在進行請求路由之前做一些前置加工,比如請求的校驗等。
在完成了pre類型的過濾器處理之後,請求進入第二個階段routing,也就是之前說的路由請求轉發階段,請求将會被routing類型過濾器處理,這裡的具體處理内容就是将外部請求轉發到具體服務執行個體上去的過程,當服務執行個體将請求結果都傳回之後,routing階段完成,請求進入第三個階段post,此時請求将會被post類型的過濾器進行處理,這些過濾器在處理的時候不僅可以擷取到請求資訊,還能擷取到服務執行個體的傳回資訊,是以在post類型的過濾器中,我們可以對處理結果進行一些加工或轉換等内容。
另外,還有一個特殊的階段error,該階段隻有在上述三個階段中發生異常的時候才會觸發,但是它的最後流向還是post類型的過濾器,因為它需要通過post過濾器将最終結果傳回給請求用戶端(實際實作上還有一些差别)
下面可以看一下Zuul自帶的核心過濾器
================================================
下面寫一個zuul,zuul工程的目錄結構如下
1.項目啟動類
package com.yxf.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
public class Zuul_8888_StartSpringCloudApp
{
public static void main(String[] args)
{
SpringApplication.run(Zuul_8888_StartSpringCloudApp.class, args);
}
}
2.application.yml檔案(注意紅色部分,配置忽略規則)
server:
port: 8888
spring:
application:
name: mymicroservicecloud-zuul-gateway
eureka:
client:
service-url:
defaultZone: http://eureka1001.com:1001/eureka,http://eureka1002.com:1002/eureka,http://eureka1003.com:1003/eureka
instance:
instance-id: gateway-8888.com
prefer-ip-address: true
zuul:
#ignored-services: microservicecloud-dept
prefix: /yxf
ignored-services: "*"
routes:
mydept.serviceId: microservicecloud-dept
mydept.path: /mydept/**
info:
app.name: yxf-microcloud
company.name: www.yxf.com
build.artifactId: $project.artifactId$
build.version: $project.version$
3.pom.xml檔案
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.yxf.springcloud</groupId>
<artifactId>mymicroservicecloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>microservicecloud-zuul-gateway-8888</artifactId>
<dependencies>
<!-- zuul路由網關 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- actuator監控 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- hystrix容錯 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- 日常标配 -->
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>microservicecloud-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- 熱部署插件 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
測試:
1.需求啟動的服務
2.Eureka
3.原來用戶端是通過ribbon或者Feign做負載均衡直接調用服務提供者(未使用zuul)
4.現在是通過網關zuul接入服務