Spring Cloud Zuul過濾器介紹及使用示例

目錄

相關知識

Zuul過濾器

        Zuul過濾器的使用方式

        Zuul過濾器的類型

        Zuul過濾器的調用順序(過濾優先級)

        Zuul調用目標服務的時機

        Zuul過濾器簡單使用示例(以pre過濾器爲例)


相關知識

       在SpringCloud微服務中,Zuul除了最常用的(動態)路由功能外,還有很多其他的功能,如過濾、認證、服務遷移、壓力測試等等,今天主要介紹Zuul的過濾器。

        默認情況下,Spring Cloud Zuul在請求路由時,會過濾掉請求頭信息中的 一些敏感信息,防止它們被傳遞到下游的外部服務器。 默認的敏感頭信息通過 zuul.sensitiveHeaders參數定義(可通過覆蓋的方式來設置),包括Cookie、Set-Cookie、Authorization 三個屬性
注:可通過覆蓋的方式來設置。如指向過濾掉Cookie、Set-Cookie,不想過濾掉Authorization ,那麼只要需要
       在application.properties文件中設置zuul.sensitiveHeaders = Cookie, Set-Cookie即可。


Zuul過濾器

Zuul過濾器的使用方式

         使用方式很簡單,繼承ZuulFilter類,重寫相應的方法即可(可詳見本文末給出的使用示例)。

Zuul過濾器的類型

  • pre:路由請求前過濾。

  • post:路由請求後(此時已經走完目標服務程序了)過濾。

  • route:路由請求時過濾。

  • error:當上述三種過濾器拋出異常時,會走error過濾。

注:如果目標服務拋出異常,並不會走error過濾器,error過濾器的“管轄範圍”只是pre、post、route這三種過濾器。

Zuul過濾器的調用順序(過濾優先級)

源碼ZuulServlet類(相關截圖)

       上圖是四種Zuul過濾器的總體過濾順序,對於同一類型的過濾器,其過濾順序是由filterOrder方法(繼承ZuulFilter類時,需要重寫此方法)的返回值決定的,filterOrder返回值越小,在同一類型種,越先過濾,此處源碼可見FilterLoader類的以下部分

Zuul調用目標服務的時機

在Zuul的衆多route類型的過濾器中,RibbonRoutingFilter過濾的run()方法裏,實現了由Zuul路由到具體的服務

Zuul過濾器簡單使用示例(以pre過濾器爲例)

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.util.RequestBodyUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Random;

/**
 * 使用ZuulFilter實現 簡單認證
 *
 * @author JustryDeng
 * @date 2019/3/1 1:36
 */
@Component
@Slf4j
@PropertySource(value = {"classpath:/authe_info.properties"}, encoding="utf8")
public class PreFilter extends ZuulFilter {

    @Value("${need-filter-uri}")
    private String[] needFilterURIs;

    /**
     * 過濾類型
     * 有:
     *  【pre】路由請求前被調用過濾、
     *  【post】後置過濾、
     *  【error】錯誤過濾、
     *  【route】路由請求時被調用
     *
     * @date 2019/3/19 14:49
     */
    @Override
    public String filterType() {
        // 設置爲 前置過濾
        return "pre";
    }

    /**
     * 設置過濾優先級
     *
     * 注:當有多個同類型(即;同filterType)的ZuulFilter的子類時,可使用此返回值指定過濾器優先級;值越小越先過濾
     *
     * @date 2019/3/19 14:55
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 設置 哪些請求 需要過濾
     *
     * @date 2019/3/19 14:55
     */
    @Override
    public boolean shouldFilter() {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        String uri = request.getRequestURI();
        // 當爲目標URI時,需要過濾
        return Arrays.asList(needFilterURIs).contains(uri);
    }

    /**
     * 實際邏輯邏輯
     *
     * 注:當RequestContext.setSendZuulResponse(false);時表示過濾失敗,zuul不對其進行路由
     */
    @Override
    public Object run() {
        // 獲取請求上下文
        RequestContext requestContext = RequestContext.getCurrentContext();

        // 獲取請求
        HttpServletRequest request = requestContext.getRequest();
        if (doFiltrate(request)) {
            // 驗證通過
            return null;
        }
        // 如果驗證不通過,那麼過濾該請求,不往下級服務去轉發請求,到此結束
        requestContext.setSendZuulResponse(false);
        requestContext.setResponseStatusCode(HttpStatus.FORBIDDEN.value());
        requestContext.setResponseBody(HttpStatus.FORBIDDEN.getReasonPhrase());
        requestContext.getResponse().setContentType("text/html;charset=UTF-8");
        return null;
    }
    
    /**
     * 進行過濾
     *
     * @param request
     *             請求
     * @return 是否通過
     * @author JustryDeng
     * @date 2019/3/1 2:13
     */
    private boolean doFiltrate (HttpServletRequest request) {
        try {
            /// 獲取請求頭
            String who = request.getHeader("Authorization");
            log.info(" requestHeader param 【Authorization】 is -> {} !", who);

            /// 向請求頭中添加信息
            // requestContext.addZuulRequestHeader("");

            // 獲取請求體
            RequestBodyUtil requestBodyUtil = new RequestBodyUtil(request);
            String requestBody = requestBodyUtil.getBody();
            log.info(" got requestBady -> {}", requestBody);

            // TODO 由於是測試代碼,這裏隨機返回 成功、失敗
            return new Random().nextBoolean();
        } catch (Exception e) {
            log.error(" zull authe occur error !", e);
            return false;
        }
    }
}

 

^_^ 如有不當之處,歡迎指正

^_^ 參考書籍
             
《Spring Cloud微服務實戰》,翟永超 著

^_^ 測試代碼託管鏈接 
               
https://github.com/JustryDeng/CommonRepository

^_^ 本文已經被收錄進《程序員成長筆記(第四部)》,筆者JustryDeng

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章