微服務網關Zuul詳解


簡述

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

  這樣存在的問題有:客戶端會請求多個不同的服務,需要維護不同的請求地址,增加開發難度。而且這樣的機制會增加身份認證的難度,每個微服務需要獨立認證。

微服務網關

  微服務網關就應運而生,微服務網關介於客戶端與服務器之間的中間層它是一個服務器,是系統對外的唯一入口。所有的外部請求都會先經過微服務網關。客戶端只需要與網關交互,只知道一個網關地址即可。

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去手動實現請求匹配,這樣做顯然就不合理。

  Zuul支持與Eureka整合開發,根據ServiceID自動的從注冊中心中獲取服務地址並轉發請求,這樣做的 好處不僅可以通過單個端點來訪問應用的所有服務,而且在添加或移除服務實例的時候不用修改Zuul的 路由配置。 

  我們首先要添加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
在其他階段發生錯誤時執行該過濾器。
  
  我們只需自定義一個filter類並繼承ZuulFilter重寫四個方法即可定義一個zuul過濾器類
  zuul提供一個RequstContext上下文對象,它內部采用ThreadLocal保存每個請求的一些信息,包括請求路由、錯誤信息、HttpServletRequest、HttpServletResponse,這使得一些操作是十分可靠的,它還擴展了ConcurrentHashMap,目的是為了在處理過程中保存任何形式的信息
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;
    }
}
zuul網關攔截器類 身份驗證簡單實現

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM