溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring Cloud Zuul中異常處理細節(jié)有哪些

發(fā)布時間:2021-12-07 11:58:06 來源:億速云 閱讀:141 作者:iii 欄目:大數(shù)據(jù)

本篇內(nèi)容主要講解“Spring Cloud Zuul中異常處理細節(jié)有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Spring Cloud Zuul中異常處理細節(jié)有哪些”吧!

首先我們來看一張官方給出的Zuul請求的生命周期圖,如下:

Spring Cloud Zuul中異常處理細節(jié)有哪些  

關于這張圖我說如下幾點:

1.正常情況下所有的請求都是按照pre、route、post的順序來執(zhí)行,然后由post返回response
2.在pre階段,如果有自定義的過濾器則執(zhí)行自定義的過濾器
3.pre、routing、post的任意一個階段如果拋異常了,則執(zhí)行error過濾器,然后再執(zhí)行post給出響應

這是這張圖給我們的信息,我們再來看看源碼com.netflix.zuul.http.ZuulServlet類中的service方法,這是整個調(diào)用過程的核心,如下:

try {
    init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);

    // Marks this request as having passed through the "Zuul engine", as opposed to servlets
    // explicitly bound in web.xml, for which requests will not have the same data attached
    RequestContext context = RequestContext.getCurrentContext();
    context.setZuulEngineRan();

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

} catch (Throwable e) {
    error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
} finally {
    RequestContext.getCurrentContext().unset();
}

我們看到這里有一個大的try…catch,大的try…catch里邊有三個小的try…catch,小的try…catch只負責捕獲ZuulException異常,其他的異常交給大的try…catch來捕獲。pre和route執(zhí)行出錯之后都會先執(zhí)行error再執(zhí)行post,而post執(zhí)行出錯之后就只執(zhí)行error而不會再執(zhí)行post。

ZuulFilter最終會在com.netflix.zuul.FilterProcessor的processZuulFilter方法中被調(diào)用,在該方法中會判斷runFilter是否執(zhí)行成功,如果執(zhí)行失敗,則將異常信息提取出來,然后拋出異常,拋出的異常如果是ZuulException的實例,則拋出一個ZuulException類型的異常,如果不是ZuulException的實例,則拋出一個狀態(tài)碼為500的ZuulException類型的異常,所以無論如何,我們最終看到的都是ZuulException類型的異常,下面我貼出processZuulFilter方法的一部分核心代碼,如下:

public Object processZuulFilter(ZuulFilter filter) throws ZuulException {
    try {
        ZuulFilterResult result = filter.runFilter();
        ExecutionStatus s = result.getStatus();
        execTime = System.currentTimeMillis() - ltime;
        switch (s) {
            case FAILED:
                t = result.getException();
                ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);
                break;
            case SUCCESS:
                break;
            default:
                break;
        }
        if (t != null) throw t;
        usageNotifier.notify(filter, s);
        return o;
    } catch (Throwable e) {
        usageNotifier.notify(filter, ExecutionStatus.FAILED);
        if (e instanceof ZuulException) {
            throw (ZuulException) e;
        } else {
            ZuulException ex = new ZuulException(e, "Filter threw Exception", 500, filter.filterType() + ":" + filterName);
            ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);
            throw ex;
        }
    }
}

在Zuul中,所有的錯誤問題的最終都是被SendErrorFilter類來處理,該類在早期的版本是一個post類型的filter,post類型的filter有一個缺陷就是不能處理post中拋出的異常,需要我們手動去完善,而我目前使用的這個版本(Dalston.SR3)已經(jīng)修復了這個問題,SendErrorFilter現(xiàn)在是一個error類型的filter,而且只要RequestContext中有異常就會進入到SendErrorFilter中,錯誤信息也都從exception對象中提取出來,核心代碼如下:

@Override
public boolean shouldFilter() {
    RequestContext ctx = RequestContext.getCurrentContext();
    // only forward to errorPath if it hasn't been forwarded to already
    return ctx.getThrowable() != null
            && !ctx.getBoolean(SEND_ERROR_FILTER_RAN, false);
}

@Override
public Object run() {
    try {
        RequestContext ctx = RequestContext.getCurrentContext();
        ZuulException exception = findZuulException(ctx.getThrowable());
        HttpServletRequest request = ctx.getRequest();

        request.setAttribute("javax.servlet.error.status_code", exception.nStatusCode);

        log.warn("Error during filtering", exception);
        request.setAttribute("javax.servlet.error.exception", exception);

        if (StringUtils.hasText(exception.errorCause)) {
            request.setAttribute("javax.servlet.error.message", exception.errorCause);
        }

        RequestDispatcher dispatcher = request.getRequestDispatcher(
                this.errorPath);
        if (dispatcher != null) {
            ctx.set(SEND_ERROR_FILTER_RAN, true);
            if (!ctx.getResponse().isCommitted()) {
                dispatcher.forward(request, ctx.getResponse());
            }
        }
    }
    catch (Exception ex) {
        ReflectionUtils.rethrowRuntimeException(ex);
    }
    return null;
}

如果我們想要自定義異常信息也很方便,如下:

@Component
public class MyErrorAttribute extends DefaultErrorAttributes {
    @Override
    public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
        Map<String, Object> result = super.getErrorAttributes(requestAttributes, includeStackTrace);
        result.put("status", 222);
        result.put("error", "error");
        result.put("exception", "exception");
        result.put("message", "message");
        return result;
    }
}

到此,相信大家對“Spring Cloud Zuul中異常處理細節(jié)有哪些”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關內(nèi)容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI