1. 程式人生 > >Spring cloud學習--Zuul02

Spring cloud學習--Zuul02

補充 過濾 logger ont try 不可預知 否則 pos RoCE

過濾器

Zuul包括兩部分內容:請求的路由和過濾。而實際上請求的路由也是通過過濾器實現的,例如理由映射主要通過pre類型的過濾器完成,它將請求路徑與配置的路由規則進行匹配,找到需要轉發的目標地址;請求轉發的部分則是由route類型的過濾器來完成的,對pre類型過濾器獲得的路由地址進行轉發。所以過濾器時Zuul實現API網關功能最為核心的部件,每一個進入Zuul的Http請求都會經過一系列的過濾器處理鏈得到請求響應並返回給客戶端。

ZuulFilter接口四特征

過濾類型、執行順序、執行條件、具體操作

  • 過濾類型 filterType
    pre:在請求被路由之前調用
    routing: 在請求路由時被調用
    post: 在routing和error過濾器之後被調用
    error: 處理請求時發生錯誤時被調用
  • 執行順序 filterOrder
    通過int值來定義過濾器的執行順序,數值越小,優先級越高
  • 執行條件 shouldFilter
    返回一個boolean值來判斷該過濾器是否要執行,可通過此方法來指定過濾器的有效範圍
  • 具體操作 run
    過濾器的具體邏輯。通過過濾邏輯來確定是否要攔截當前的請求,否則對請求進行一些加工

核心過濾器

過濾器類型 順序 過濾器 功能
pre -3 ServletDetectionFilter 標記處理Servlet的類型
pre -2 Servlet30WrapperFilter 包裝HttpServletRequest請求
pre -1 FormBodyWrapperFilter 包裝請求體
pre 1 DebugFilter 標記調試標誌
pre 5 PreDecorationFilter 處理請求上下文供後續使用
route 10 RibbonRoutingFilter serviceId請求轉發
route 100 SimpleHostRoutingFilter url請求轉發
route 500 SendForwordFilter forward請求轉發
post 0 SendErrorFilter 處理有錯誤的請求響應
post 1000 SendResponseFilter 處理正常處理的請求響應

異常處理

已知異常處理

對於可預知異常處理,可以使用SendErrorFilter處理
SendErrorFilter過濾器對異常處理的觸發條件是,異常信息必須包含error.status_code錯誤信息,所以在進行異常處理的時候需要在異常信息中添加error.status_code信息用來出發SendErrorFilter。

未知異常處理

對於不可預知的異常需要使用全局異常處理,即使用ErrorFilter處理
在請求生命周期的pre、route、post三個階段中有異常拋出的時候都會進入error階段的處理,所以可以創建一個error類型的過濾器來捕獲這些異常信息,並根據這些異常信息在請求上下文中註入需要返回給客戶端的錯誤描述。常見用法是,在try-catch中註入error信息,讓SendErrorFilter捕獲處理返回給客戶端,eg:

public class ErrorFilter extends ZuulFilter
{
    private static final Logger log = LoggerFactory.getLogger(ErrorFilter.class);
    @Override
    public String filterType()
    {
        return "error";
    }

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

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

    @Override
    public Object run()
    {
        RequestContext ctx = RequestContext.getCurrentContext();
        Throwable throwable = ctx.getThrowable();
        log.error("this is a ErrorFilter:{}.", throwable.getCause().getMessage());
        ctx.set("error.status_code", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        ctx.set("error.exception", throwable.getCause());
        return null;
    }
}

第一種是在開發過程中對異常的處理,第二種是對第一種的補充,防止意外異常發生

三種過濾器類型調用過程

try{
preRoute();
}catch(ZuulException e){
    error(e);
    postRoute();
    return;
}
try{
    route();
}catch(ZuulException e){
    error(e);
    postRoute();
    return;
}
try{
    postRoute();
}catch(ZuulException){
    error(e);
    return;
}

在pre、route過濾器調用過程中,拋出異常都要經過error過濾器處理,然後再通過post返回客戶端。但是,**如果在post中出現了異常,由error過濾器處理後並不會再調用post階段的請求,這些error.*參數就不會被SendErrorFilter消費輸出,會造成異常泄露**。

處理方法

在error過濾器之後在加一層SendErrorFilter,用來執行post過濾器中拋出的異常

public class ErrorExtFilter extends SendErrorFilter
{
    @Override
    public String filterType()
    {
        return "error";
    }

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

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

那麽怎樣判斷過濾器來自於哪個階段呢,需要重寫FilterProcessor核心過濾器類,在執行filter具體邏輯的方法processZuulFilter方法中對處理的filter進行標記

public class MarkFilterProcessor extends FilterProcessor
{
    @Override
    public Object processZuulFilter(ZuulFilter filter) throws ZuulException
    {
        try
        {
            return super.processZuulFilter(filter);
        }
        catch (ZuulException e)
        {
            RequestContext ctx = RequestContext.getCurrentContext();
            ctx.set("failed.filter", filter);
            throw e;
        }
    }
}

在shouldFilter方法中進行判斷是不是post階段拋出的異常

@Override
    public boolean shouldFilter()
    {
        RequestContext ctx = RequestContext.getCurrentContext();
        ZuulFilter failedFilter = (ZuulFilter) ctx.get("failed.filter");
        if(failedFilter != null && failedFilter.filterType().equals("post"))
        {
            return true;
        }
        return false;
    }

最後在主類中調用FilterProcessor.setProcessor(new MarkFilterProcessor());啟動自定義的核心處理器

自定義異常信息

默認使用DefaultErrorAttributes作為默認異常信息接口,如果有ErrorAttributes接口的實現類,則不適用默認的,而使用實現類

  • 自定義實現類,重寫getErrorAttributes方法
    移除message中的exception屬性
public class MessageErrorAttributes extends DefaultErrorAttributes
{
    @Override
    public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace)
    {
        Map<String, Object> result = super.getErrorAttributes(requestAttributes, includeStackTrace);
        result.remove("exception");
        return result;
    }
}
  • 加入主類
public DefaultErrorAttributes errorAttributes()
{
    return new MessageErrorAttributes();
}

禁用過濾器(包括自定義+默認)

zuul.<filtername>.<filtertype>.disable=true

動態路由

使用spring cloud config分布式配置中心實現application.properties/application.yarm動態加載

動態過濾器

Spring cloud學習--Zuul02