Zuul的核心是過濾器,通過這些過濾器我們可以擴展出很多功能,比如:
- 動態路由:動態地將客戶端的請求路由到後端不同的服務,做一些邏輯處理,比如聚合多個服務的數據返回。
請求監控:可以對整個系統的請求進行監控,記錄詳細的請求響應日誌,可以實時統計出當前系統的訪問量以及監控狀態。 - 認證鑑權:對每一個訪問的請求做認證,拒絕非法請求,保護好後端的服務。
- 壓力測試:壓力測試是一項很重要的工作,像一些電商公司需要模擬更多真實的用戶併發量來保證重大活動時系統的穩定。通過Zuul可以動態地將請求轉發到後端服務的集羣中,還可以識別測試流量和真實流量,從而做一些特殊處理。
- 灰度發佈:灰度發佈可以保證整體系統的穩定,在初始灰度的時候就可以發現、調整問題,以保證其影響度。
使用Zuul構建微服務網關
-
基本環境
參考:https://blog.csdn.net/admin_15082037343/article/details/107134802 -
新建子模塊:demo-zuul,添加依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
- 啓動類
package com.demo.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
- application.yml
server:
port: 8080
spring:
application:
name: demo-zuul
zuul:
routes:
demo-client:
path: /user/**
eureka:
client:
service-url:
defaultZone: http://admin:[email protected]:8761/eureka/
這裏表示對/user/**的訪問會轉發到demo-client上
訪問http://127.0.0.1:8080/user/user/4028a881727903dc017279105f520002
Zuul過濾器類型
Zuul中的過濾器總共有4種類型,每種類型都有對應的使用場景。
- pre:可以在請求被路由之前調用。適用於身份認證的場景,認證通過後再繼續執行下面的流程。
- route:在路由請求時被調用。適用於灰度發佈場景,在將要路由的時候可以做一些自定義的邏輯。
- post:在route和error過濾器之後被調用。這種過濾器將請求路由到達具體的服務之後執行。適用於需要添加響應頭,記錄響應日誌等應用場景。
- error:處理請求時發生錯誤時被調用。在執行過程中發送錯誤時會進入error過濾器,可以用來統一記錄錯誤信息。
定義一個pre類型的過濾器
package com.demo.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.stereotype.Component;
@Component
public class MyFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
// 當前請求上下文
RequestContext requestContext = RequestContext.getCurrentContext();
String name = requestContext.getRequest().getParameter("name");
if (name == null || name.trim().isEmpty()) {
// 不需要將當前請求轉發到後端
requestContext.setSendZuulResponse(false);
// 客戶端響應
requestContext.setResponseBody("error");
}
return null;
}
}
filterOrder():當前過濾器的執行順序,數字越小越先執行
shouldFilter():true代表執行當前過濾器,false代表不執行
run():邏輯處理,RequestContext.getCurrentContext()獲取當前請求上下文。
RequestContext對象的set()方法可以向下一個過濾器傳遞參數,如下:
// 存值
requestContext.set("name", "zhangsan");
// 取值
requestContext.get("name")