Spring cloud学习--Zuul02

Posted [烟火里的尘埃]

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring cloud学习--Zuul02相关的知识,希望对你有一定的参考价值。

过滤器

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的主要内容,如果未能解决你的问题,请参考以下文章

spring cloud 学习笔记--网关zuul学习

spring cloud深入学习-----Spring Cloud Zuul网关 Filter熔断重试高可用的使用方式

spring cloud 学习之路由网关(zuul)

spring cloud 学习 - zuul 微服务网关

spring cloud深入学习-----服务网关zuul

总结学习Spring Cloud系列之深入理解Zuul