天天看點

springcloud 網關_Spring Cloud 系列之 Netflix Zuul 服務網關(二)

springcloud 網關_Spring Cloud 系列之 Netflix Zuul 服務網關(二)

本篇文章為系列文章,未讀第一集的同學請猛戳這裡:

哈喽沃德先生:Spring Cloud 系列之 Netflix Zuul 服務網關(一)​zhuanlan.zhihu.com

springcloud 網關_Spring Cloud 系列之 Netflix Zuul 服務網關(二)

本篇文章講解 Zuul 網關過濾器實作統一鑒權以及網關過濾器異常統一處理。

網關過濾器

springcloud 網關_Spring Cloud 系列之 Netflix Zuul 服務網關(二)

https://www.zhihu.com/video/1234207041360777216

springcloud 網關_Spring Cloud 系列之 Netflix Zuul 服務網關(二)

Zuul 包含了對請求的路由和過濾兩個核心功能,其中路由功能負責将外部請求轉發到具體的微服務執行個體上,是實作外部通路統一入口的基礎;而過濾器功能則負責對請求的處理過程進行幹預,是實作請求校驗,服務聚合等功能的基礎。然而實際上,路由功能在真正運作時,它的路由映射和請求轉發都是由幾個不同的過濾器完成的。

路由映射主要通過

pre

類型的過濾器完成,它将請求路徑與配置的路由規則進行比對,以找到需要轉發的目标位址;而請求轉發的部分則是由

routing

類型的過濾器來完成,對

pre

類型過濾器獲得的路由位址進行轉發。是以說,過濾器可以說是 Zuul 實作 API 網關功能最核心的部件,每一個進入 Zuul 的 http 請求都會經過一系列的過濾器處理鍊得到請求響應并傳回給用戶端。

關鍵名詞

  • 類型 :定義路由流程中應用過濾器的階段。共 pre、routing、post、error 4 個類型。
  • 執行順序 :在 同類型 中,定義過濾器執行的順序。比如多個 pre 類型的執行順序。
  • 條件 :執行過濾器所需的條件。true 開啟,false 關閉。
  • 動作 :如果符合條件,将執行的動作。具體操作。

過濾器類型

  • pre:請求被路由到源伺服器之前執行的過濾器
    • 身份認證
    • 選路由
    • 請求日志
  • routing:處理将請求發送到源伺服器的過濾器
  • post:響應從源伺服器傳回時執行的過濾器
    • 對響應增加 HTTP 頭
    • 收集統計和度量名額
    • 将響應以流的方式發送回用戶端
  • error:上述階段中出現錯誤時執行的過濾器

入門案例

建立過濾器

Spring Cloud Netflix Zuul 中實作過濾器必須包含 4 個基本特征:過濾器類型,執行順序,執行條件,動作(具體操作)。這些步驟都是

ZuulFilter

接口中定義的 4 個抽象方法:

package com.example.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * 網關過濾器
 */
@Component
public class CustomFilter extends ZuulFilter {

    private static final Logger logger = LoggerFactory.getLogger(CustomFilter.class);

    /**
     * 過濾器類型
     *      pre
     *      routing
     *      post
     *      error
     *
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 執行順序
     *      數值越小,優先級越高
     *
     * @return
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 執行條件
     *      true 開啟
     *      false 關閉
     *
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 動作(具體操作)
     *      具體邏輯
     *
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        // 擷取請求上下文
        RequestContext rc = RequestContext.getCurrentContext();
        HttpServletRequest request = rc.getRequest();
        logger.info("CustomFilter...method={}, url={}",
                request.getMethod(),
                request.getRequestURL().toString());
        return null;
    }

}
           
  • filterType

    :該函數需要傳回一個字元串代表過濾器的類型,而這個類型就是在 http 請求過程中定義的各個階段。在 Zuul 中預設定義了 4 個不同的生命周期過程類型,具體如下:
    • pre:請求被路由之前調用
    • routing: 路由請求時被調用
    • post: routing 和 error 過濾器之後被調用
    • error:處理請求時發生錯誤時被調用
  • filterOrder

    :通過 int 值來定義過濾器的執行順序,數值越小優先級越高。
  • shouldFilter

    :傳回一個 boolean 值來判斷該過濾器是否要執行。
  • run

    :過濾器的具體邏輯。在該函數中,我們可以實作自定義的過濾邏輯,來确定是否要攔截目前的請求,不對其進行後續路由,或是在請求路由傳回結果之後,對處理結果做一些加工等。

通路

通路:http://localhost:9000/product-service/product/1 控制台輸出如下:

CustomFilter...method=GET, url=http://localhost:9000/product-service/product/1
           

統一鑒權

接下來我們在網關過濾器中通過 token 判斷使用者是否登入,完成一個統一鑒權案例。

建立過濾器

package com.example.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 權限驗證過濾器
 */
@Component
public class AccessFilter extends ZuulFilter {

    private static final Logger logger = LoggerFactory.getLogger(AccessFilter.class);

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        // 擷取請求上下文
        RequestContext rc = RequestContext.getCurrentContext();
        HttpServletRequest request = rc.getRequest();
        // 擷取表單中的 token
        String token = request.getParameter("token");
        // 業務邏輯處理
        if (null == token) {
            logger.warn("token is null...");
            // 請求結束,不在繼續向下請求。
            rc.setSendZuulResponse(false);
            // 響應狀态碼,HTTP 401 錯誤代表使用者沒有通路權限
            rc.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
            // 響應類型
            rc.getResponse().setContentType("application/json; charset=utf-8");
            PrintWriter writer = null;
            try {
                writer = rc.getResponse().getWriter();
                // 響應内容
                writer.print("{"message":"" + HttpStatus.UNAUTHORIZED.getReasonPhrase() + ""}");
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (null != writer)
                    writer.close();
            }
        } else {
            // 使用 token 進行身份驗證
            logger.info("token is OK!");
        }
        return null;
    }

}
           

通路

通路:http://localhost:9000/product-service/product/1 結果如下:

springcloud 網關_Spring Cloud 系列之 Netflix Zuul 服務網關(二)

通路:http://localhost:9000/product-service/product/1?token=abc123 結果如下:

springcloud 網關_Spring Cloud 系列之 Netflix Zuul 服務網關(二)

Zuul 請求的生命周期

springcloud 網關_Spring Cloud 系列之 Netflix Zuul 服務網關(二)
  1. HTTP 發送請求到 Zuul 網關
  2. Zuul 網關首先經過 pre filter
  3. 驗證通過後進入 routing filter,接着将請求轉發給遠端服務,遠端服務執行完傳回結果,如果出錯,則執行 error filter
  4. 繼續往下執行 post filter
  5. 最後傳回響應給 HTTP 用戶端

網關過濾器異常統一處理

springcloud 網關_Spring Cloud 系列之 Netflix Zuul 服務網關(二)

https://www.zhihu.com/video/1234207208662945792

建立過濾器

package com.example.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.PrintWriter;

/**
 * 異常過濾器
 */
@Component
public class ErrorFilter extends ZuulFilter {

    private static final Logger logger = LoggerFactory.getLogger(ErrorFilter.class);

    @Override
    public String filterType() {
        return "error";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext rc = RequestContext.getCurrentContext();
        Throwable throwable = rc.getThrowable();
        logger.error("ErrorFilter..." + throwable.getCause().getMessage(), throwable);
        // 響應狀态碼,HTTP 500 伺服器錯誤
        rc.setResponseStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
        // 響應類型
        rc.getResponse().setContentType("application/json; charset=utf-8");
        PrintWriter writer = null;
        try {
            writer = rc.getResponse().getWriter();
            // 響應内容
            writer.print("{"message":"" + HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase() + ""}");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != writer)
                writer.close();
        }
        return null;
    }

}
           

模拟異常

在 pre 過濾器中添加模拟異常代碼。

// 模拟異常
Integer.parseInt("zuul");
           

配置檔案

禁用 Zuul 預設的異常處理 filter:

SendErrorFilter

zuul:
  # 禁用 Zuul 預設的異常處理 filter
  SendErrorFilter:
    error:
      disable: true
           

通路

通路:http://localhost:9000/product-service/product/1 結果如下:

springcloud 網關_Spring Cloud 系列之 Netflix Zuul 服務網關(二)
下一篇我們講解 Zuul 和 Hystrix 的無縫結合,實作網關監控、網關熔斷、網關限流、網關調優,記得關注噢~
springcloud 網關_Spring Cloud 系列之 Netflix Zuul 服務網關(二)

大家可以通過

分類

檢視更多關于

Spring Cloud

的文章。

本文采用

知識共享「署名-非商業性使用-禁止演繹 4.0 國際」許可協定

您的

點贊

轉發

是對我最大的支援。

掃碼關注

哈喽沃德先生

「文檔 + 視訊」每篇文章都配有專門視訊講解,學習更輕松噢 ~

springcloud 網關_Spring Cloud 系列之 Netflix Zuul 服務網關(二)