一、 描述 Spring Cloud Zuul是基於Netflix開源的Zuul項目構建而成,它作為微服務架構中的網關服務,主要用於實現動態路由、負載均衡和請求過濾等功能。 動態路由:Zuul根據預設的路由規則將進來的請求路由到相應的服務實例上。路由規則可以通過配置文件或代碼進行定義,接收到請求後, ...
一、 描述
Spring Cloud Zuul是基於Netflix開源的Zuul項目構建而成,它作為微服務架構中的網關服務,主要用於實現動態路由、負載均衡和請求過濾等功能。
-
動態路由:Zuul根據預設的路由規則將進來的請求路由到相應的服務實例上。路由規則可以通過配置文件或代碼進行定義,接收到請求後,Zuul會解析請求的URL,並根據配置的路由規則找到對應的服務地址,將請求轉發到目標服務。
-
負載均衡:Zuul內置了Ribbon負載均衡器,可以對請求進行負載均衡。當一個服務有多個實例時,Zuul可以使用負載均衡演算法將請求均勻地分發到不同的實例上,以提高系統的性能和可擴展性。
-
請求過濾:Zuul支持自定義過濾器,在請求被路由之前或之後對請求進行處理。過濾器可以用於在路由前進行身份驗證、請求統計、參數校驗等操作,也可以在路由後處理響應結果,比如修改返回數據、添加自定義的響應頭等。開發者可以根據需求創建不同類型的過濾器,並定義過濾器的執行順序。
-
整合服務註冊中心:Zuul可以與服務註冊中心(如Zookeeper、Eureka)進行整合,實現動態路由和負載均衡。通過與服務註冊中心交互,Zuul能夠動態地獲取服務實例的信息,並根據需要進行路由和負載均衡。
-
高可用和容錯:Zuul支持配置多個實例運行在不同的機器上,以實現高可用性。當一個Zuul實例發生故障時,其他實例可以接管請求處理,確保系統的穩定性和容錯性。
Spring Cloud Zuul通過動態路由、負載均衡和請求過濾等機制,提供了一個強大且靈活的網關服務。它能夠統一管理微服務的入口,實現請求的轉發和過濾,簡化了微服務架構中的通信和調用方式,提高了系統的可伸縮性和可維護性。
下麵是使用Spring Cloud Zuul的一般實踐步驟
二、添加依賴
引入zuul的依賴spring-cloud-starter-netflix-zuul
1 <dependency> 2 <groupId>org.springframework.cloud</groupId> 3 <artifactId>spring-cloud-starter-netflix-zuul</artifactId> 4 </dependency>View Code
三、創建啟動類:
創建一個啟動類,並使用@EnableZuulProxy
註解開啟Zuul代理功能。
1 @SpringBootApplication 2 @EnableZuulProxy 3 public class GatewayApplication { 4 5 public static void main(String[] args) { 6 SpringApplication.run(GatewayApplication.class, args); 7 } 8 9 }View Code
四、 配置
在配置文件(如application.yml
)中定義Zuul的路由規則。可以使用Zuul的zuul.routes
首碼來配置不同的路由規則。
1 server: 2 port: 9000 3 management: 4 endpoints: 5 web: 6 exposure: 7 include: '*' 8 server: 9 port: 12345 10 zuul: 11 routes: 12 configserver: 13 path: /myConfig/** 14 serviceId: config 15 user: 16 path: /myUser/** 17 serviceId: provider 18 ignored-patterns: #忽略指定的路由 19 - /config/** 20 - /gateway/** 21 sensitive-headers: 22 # ignore-local-service: true # 忽略原來自身的路由。比如,true: 原來的config/xxx/xxx不可再訪問View Code
上述配置將/myConfig/**的請求轉發到config服務,將/myUser/**的請求轉發到provider服務。
還可以將網關註冊到註冊中心實現高可用。創建bootstrap.yml文件
1 spring: 2 application: 3 name: gateway 4 cloud: 5 zookeeper: 6 discovery: 7 register: true 8 enabled: true 9 connect-string: 192.168.3.100:2181 10 config: 11 discovery: 12 service-id: config 13 enabled: trueView Code
五、配置過濾器
通過zuul添加過濾器,對請求進行攔截或校驗等等
1 package com.mike.study.gateway.fiter; 2 3 import com.netflix.zuul.ZuulFilter; 4 import com.netflix.zuul.context.RequestContext; 5 import com.netflix.zuul.exception.ZuulException; 6 import org.apache.commons.lang.StringUtils; 7 import org.springframework.http.HttpStatus; 8 import org.springframework.stereotype.Component; 9 10 import javax.servlet.http.HttpServletRequest; 11 12 import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER; 13 import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE; 14 15 /** 16 * @Classname ParameterFilter 17 * @Created by Michael 18 * @Date 2023/7/12 19 * @Description 自定義過濾器 20 */ 21 @Component 22 public class ParameterFilter extends ZuulFilter { 23 /** 24 * 前置過濾 25 * @return 26 */ 27 @Override 28 public String filterType() { 29 return PRE_TYPE; 30 } 31 32 /** 33 * 數值越小,優先順序越高 34 * @return 35 */ 36 @Override 37 public int filterOrder() { 38 return PRE_DECORATION_FILTER_ORDER - 1; 39 } 40 41 @Override 42 public boolean shouldFilter() { 43 return true; 44 } 45 46 @Override 47 public Object run() throws ZuulException { 48 49 // 獲取請求對象 50 RequestContext context = RequestContext.getCurrentContext(); 51 HttpServletRequest request = context.getRequest(); 52 // 獲取地址欄傳入的參數 53 String token = request.getParameter("token"); 54 System.out.println("token ===>"+token); 55 //模擬校驗token,沒有token則終止轉發 56 if (StringUtils.isEmpty(token)) { 57 context.setSendZuulResponse(false); 58 context.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); 59 } 60 return null; 61 } 62 }ParameterFilter.java
以上代碼時在轉發請求服務前,對參數進行校驗,如果沒有token參數,則停止轉發,並且返回401錯誤
六、測試
測試網關轉發主要需要請求發起方,網關和請求處理方。這裡在原來demo的基礎上,增加網關,所以看到有配置中心,以往的文章有項目的搭建介紹。如果不想那麼複雜,可以去掉配置中心,將配置放置各個module即可,項目組如下
準備請求發起方,即consumer,controller通過feign框架請求網關,網關轉發請求provider。consumer的controller如下
1 import com.mike.study.orderconsumer.client.UserClient; 2 import com.mike.study.orderconsumer.vo.UserVo; 3 import org.springframework.web.bind.annotation.GetMapping; 4 import org.springframework.web.bind.annotation.PathVariable; 5 import org.springframework.web.bind.annotation.RequestParam; 6 import org.springframework.web.bind.annotation.RestController; 7 8 import javax.annotation.Resource; 9 10 /** 11 * @Classname UserRuttingController 12 * @Created by Michael 13 * @Date 2023/7/9 14 * @Description feign框架調用provider api 15 */ 16 @RestController 17 public class UserRuttingController { 18 @Resource 19 private UserClient userClient; 20 21 @GetMapping("warp/user/2.1/{id}") 22 public UserVo getUser(@PathVariable("id") Integer userId, @RequestParam("token") String token) { 23 System.out.println("使用feign框架調用provide的api"); 24 return userClient.getUser(userId, token); 25 } 26 }controller
Feign介面
1 import com.mike.study.orderconsumer.vo.UserVo; 2 import org.springframework.cloud.openfeign.FeignClient; 3 import org.springframework.web.bind.annotation.GetMapping; 4 import org.springframework.web.bind.annotation.PathVariable; 5 import org.springframework.web.bind.annotation.RequestParam; 6 7 /** 8 * @Classname UserFeigClient 9 * @Created by Michael 10 * @Date 2023/7/9 11 * @Description feign client 12 */ 13 14 @FeignClient("gateway") 15 public interface UserClient { 16 17 @GetMapping("myUser/user/{id}") 18 public UserVo getUser(@PathVariable("id") Integer userId,@RequestParam("token") String token); 19 }UserClient
以上Feign介面配合註冊中心zookeeper使用,訪問的網關地址,而不是直接請求服務提供者的api。
provider module簡單提供一個api查詢用戶信息。
六、測試結果
positive case:token參數有值
negative case:token參數i為空
總結,就是consumer不再直接請求provider server,而是通過zuul作為中轉站,這樣做的好處很多,比如,對consumer的請求進行攔截過濾,驗證,降流等等。
如果該文章對你有所幫助,請點個贊支持下,謝謝!