Zuul的作用
Zuul是spring cloud中推薦使用的api網關,一般來說,服務是叢集部署的,并且不會直接暴露到外網中直接調用,外部用戶端想要調用服務無法直接調用服務的實際位址,實際情況也不允許這樣做,這時候就需要通過一個稱為網關的元件來處理用戶端的請求,通過網關來進行配置設定,zuul的主要功能就是對所有的服務請求進行統一攔截管理,通過負載均衡分發服務請求,與Nginx類似,同時,zuul還可以對服務請求進行監控、日志管理、驗簽等操作,zuul就像一個守門神,對所有要進城的人進行篩查、登記,然後配置設定到具體要去的地方。
總的來說,zuul可以實作反向代理、負載均衡、限流、監控、日志、驗簽等操作。
Zuul與Nginx的差別
相同點:可以實作反向代理、負載均衡,都是網關
差別:
Zuul:java語言編寫,主要适用于微服務架構下的,是在用戶端做負載均衡
Nginx:C語言編寫,在伺服器端做負載均衡,更适用于對外部的請求進行分發,從功能上來說,Nginx比Zuul更強大,還可以通過一些腳本來擴充功能,Zuul的功能,Nginx也可以實作,但是很麻煩,需要用其他的語言實作。
搭建Zuul網關
1.引入zuul和eureka用戶端依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.啟動類開啟zuul,@EnableZuulProxy
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args){
SpringApplication.run(ZuulApplication.class,args);
}
}
3.配置路由
#zuul路由配置
zuul:
routes:
#路由名稱,命名無強制要求
eureka-client:
#比對的請求路徑
path: /eureka-client-zuul/**
#實際轉發的服務别名
serviceId: eureka-client
eureka-feign-client:
path: /eureka-feign-client-zuul/**
serviceId: eureka-feign-client
zuul的原理
zuul實際上也是一個服務,其核心元件其實是過濾器,zuul的路由轉發實際上是通過一層一層不同類型的過濾器實作的,按照順序主要分為幾種:
pre
pre過濾器可以了解為預處理,是最先經過的過濾器,在請求還沒有被轉發之前被調用,常用來用來做驗簽、黑白名單處理,主要做了幾個工作:
1.判斷request的涞源
2.将HttpServletRequest包裝成特定對象
3.将content-type為特定類型的request包裝成特定對象
4.處理debug資訊
5.進行路由規則比對等預處理操作
route
route過濾器主要是對請求進行轉發,route隻會對指定了serviceId的請求進行處理,在route過濾器中将會通過Ribbon以及Hystrix實作負載均衡和限流,是zuul的核心。
1.比對path中符合規則的請求路徑
2.根據serviceid從eureka中擷取服務位址
3.通過Ribbon做負載均衡擷取具體調用位址
4.通過httpclient方式進行服務調用
post
post過濾器是在服務完成調用之後,請求已經處理完,結果傳回到用戶端之前調用的,無論是在調用過程中成功與否,最終都會通過post過濾器,在這裡可以對響應進行處理
error
error過濾器就是在上面三個過濾器發生異常的時候會觸發,但最終還是需要通過post過濾器将響應傳回給用戶端
關于zuul過濾器的具體實作原理參考:
https://www.jianshu.com/p/ff863d532767
https://www.cnblogs.com/trust-freedom/p/9982680.html
自定義Zuul過濾器實作
1.繼承ZuulFilter
2.指定過濾器的類型,實作filterType方法(pre、route、post、error)
3.指定過濾器的順序,filterOrder方法,預設是0,所有的過濾器都有自己的順序,包括zuul自己的過濾器,具體順序可以參考上面貼出的連結,裡面有詳細解釋
4.設定是否執行過濾器,shouldFilter方法,傳回true/false,設定為false的話,過濾器的邏輯便不會被執行
5.實作過濾器的業務邏輯,run方法,下面是一個例子驗證是否請求中是否帶有userToken參數,如果沒有則不做轉發,傳回提示。
6.通過注解@Component将自定義過濾器加入到spring容器當中
@Component
public class TokenFilter extends ZuulFilter {
@Autowired
HttpServletRequest request;
//過濾器的類型
//pre:可以在請求被路由之前調用
//routing: 路由請求時被調用
//post:在routing和error過濾器之後被調用
//error:處理請求時發生錯誤時被調用
@Override
public String filterType() {
return "pre";
}
//過濾器的順序
@Override
public int filterOrder() {
return 0;
}
//過濾器是否要執行
@Override
public boolean shouldFilter() {
return true;
}
//過濾器業務邏輯,舉例驗證是否有userToken參數
@Override
public Object run() throws ZuulException {
String token = request.getParameter("userToken");
if (StringUtils.isEmpty(token)){
//擷取目前上下文
RequestContext currentContext = RequestContext.getCurrentContext();
//設定不轉發zuul請求
currentContext.setSendZuulResponse(false);
//設定攔截傳回的提示
currentContext.setResponseBody("token is empty");
//設定狀态碼
currentContext.setResponseStatusCode(400);
return null;
}
return null;
}
}