千家信息网

Spring Cloud Zuul中异常处理细节有哪些

发表于:2025-01-23 作者:千家信息网编辑
千家信息网最后更新 2025年01月23日,本篇内容主要讲解"Spring Cloud Zuul中异常处理细节有哪些",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Spring Cloud Zuul中
千家信息网最后更新 2025年01月23日Spring Cloud Zuul中异常处理细节有哪些

本篇内容主要讲解"Spring Cloud Zuul中异常处理细节有哪些",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Spring Cloud Zuul中异常处理细节有哪些"吧!

首先我们来看一张官方给出的Zuul请求的生命周期图,如下:

关于这张图我说如下几点:

1.正常情况下所有的请求都是按照pre、route、post的顺序来执行,然后由post返回response
2.在pre阶段,如果有自定义的过滤器则执行自定义的过滤器
3.pre、routing、post的任意一个阶段如果抛异常了,则执行error过滤器,然后再执行post给出响应

这是这张图给我们的信息,我们再来看看源码com.netflix.zuul.http.ZuulServlet类中的service方法,这是整个调用过程的核心,如下:

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执行出错之后都会先执行error再执行post,而post执行出错之后就只执行error而不会再执行post。

ZuulFilter最终会在com.netflix.zuul.FilterProcessor的processZuulFilter方法中被调用,在该方法中会判断runFilter是否执行成功,如果执行失败,则将异常信息提取出来,然后抛出异常,抛出的异常如果是ZuulException的实例,则抛出一个ZuulException类型的异常,如果不是ZuulException的实例,则抛出一个状态码为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)已经修复了这个问题,SendErrorFilter现在是一个error类型的filter,而且只要RequestContext中有异常就会进入到SendErrorFilter中,错误信息也都从exception对象中提取出来,核心代码如下:

@Overridepublic 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);}@Overridepublic 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;}

如果我们想要自定义异常信息也很方便,如下:

@Componentpublic class MyErrorAttribute extends DefaultErrorAttributes {    @Override    public Map getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {        Map 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中异常处理细节有哪些"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

0