springcloud-zuul詳解

源碼解析

  • Spring.factories中加載了ZuulServerAutoConfiguration和ZuulProxyAutoConfiguration
  • ZuulServerAutoConfiguration中註冊了FilterRegistrationBean
  • FilterRegistrationBean設置new了一個ZuulServletFilter
  • ZuulServletFilter實現了Filter接口,並在doFilter中調用了zuul的幾個filter
try {
                preRouting();
            } catch (ZuulException e) {
                error(e);
                postRouting();
                return;
            }
            
            // Only forward onto to the chain if a zuul response is not being sent
            if (!RequestContext.getCurrentContext().sendZuulResponse()) {
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }
            
            try {
                routing();
            } catch (ZuulException e) {
                error(e);
                postRouting();
                return;
            }
            try {
                postRouting();
            } catch (ZuulException e) {
                error(e);
                return;
            }
  • 只有在pre階段設置zuulResponse爲false,才能阻止之後過濾器的執行
  • Post過濾器主要有兩個
    • sendError:order=0,
    • sendResponse:order=1000,優先在responseBody中獲取數據,其次在responseDataStream中獲取。可以在error過濾器中設置錯誤信息,在errorController中獲取,返回詳細錯誤信息。
  • 過濾器中的異常處理

在sendErrorFilter中是這樣判斷異常的

所以在過濾器中要設置異常,

  • 默認異常信息源碼解析
    1. SendErrorFilter會轉發到/error端點
    2. /error端點由BasicErrorController來提供
    3. 調用getErrorAttributes來組織錯誤信息
    4. 利用ErrorAttributes接口的實現,默認實現是DefaultErrorAttributes
    5. 該實現有註解@ConditionalOnMissingBean

應用

  • 自定義異常信息,多種方式
    1. 提供一個ErrorAttributes的實現類
    2. 有異常信息時使用,將請求轉發到/error,可以通過實現errorController,並在裏面添加/error的requestMapping方法,自定義錯誤信息
    3. 禁用error過濾器,自定義error過濾器返回數據
  • 獲取接口調用的返回值,可以參考SendResponseFilter的實現,獲取完之後一定要重新設置返回值,例如
@Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        if(ctx.getResponseBody() != null){
            System.out.println(ctx.getResponseBody());
        }else{
            InputStream is = ctx.getResponseDataStream();
            try {
                byte[] b = new byte[10];

                int len = -1;
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                while ((len = is.read(b)) != -1){
                    bos.write(b, 0, len);
                }

                String r = new String(bos.toByteArray());
                System.out.println(r);
                //次處很重要
                ctx.setResponseBody(r);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

 

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