Spring Cloud Zuul(API网关服务)(3)

过滤器

在Spring Cloud Zuul中实现的过滤器必须包含4个基本特征:过滤类型,执行顺序,执行条件,具体操作。这就是ZuulFilter接口中定义的4个抽象方法:

    public abstract String filterType();

    public abstract int filterOrder();

    boolean shouldFilter();

    Object run() throws ZuulException;

1.filterType:该函数返回一个字符串来代表过滤器的类型,而这个类型就是在HTTP请求过程中定义的各个阶段。在Zuul中默认定义了4种不同生命周期的过滤类型,如:

    1.pre:可以在请求被路由之前调用。

    2.routing:在路由请求时被调用。

    3.post:在routing和error过滤器之后被调用。

    4.error:处理请求时发生错误时被调用。

2.filterOrder:通过int值来定义过滤器的执行顺序,数值越小优先级越高。

3.shouldFilter:返回一个boolean值来判断该过滤器是否要执行。我们可以通过此方法来指定过滤器的有效范围。

4.run:过滤器的具体逻辑。在该函数中,我们可以实现自定义的过滤逻辑,来确定是否要拦截当前的请求,不对其进行后续路由,或是在请求路由返回结果之后,对处理结果做一些加工等。

请求声明周期

当HTTP请求到达API网关服务的时候,首先会进入第一个阶段pre,在这里他会被pre类型的过滤器进行处理,该类型过滤器的主要目的是在进行请求路由之前做一些前置加工,比如请求的校验等。在完成了pre类型的过滤器处理之后请求进入第二个阶段routing(请求转发阶段),请求将会被routing类型过滤器处理。这里的具体处理内容就是将外部请求转发到具体服务实例上去的过程,当服务实例将请求结果都返回之后,routing阶段完成,请求进入第三个阶段post,此时请求将会被post类型的过滤器进行处理,这些过滤器在处理的时候不仅可以获取到请求信息,还能获取到服务实例的返回信息,所以在post类型的过滤器中,我们可以对处理结果进行一些加工或转换等内容。另外,还有一个特殊的阶段error,该阶段只有在上述三个阶段中发生异常的时候才会触发,但是它的最后流向还是post类型的过滤器,因为它需要通过post过滤器将最终结果返回给请求客户端。

异常处理

try-catch处理

在post过滤器中SendErrorFilter是用来处理异常信息。它会调用这个方法:

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

该方法的返回值中有个判断依据ctx.containsKey("error.status_code")也就是说请求上下文中必须有error.status_code参数,我们实现的ThorwExceptionFilter中没有设置这个参数,所以不会进入SendErrorFilter过滤器的处理逻辑。下面修改下Filter过滤器:

@Component
public class AccessFilter extends ZuulFilter {

    private static Logger log=LoggerFactory.getLogger(AccessFilter.class);

    @Override
    public String filterType() {
        return "pre";
    }

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

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

    @Override
    public Object run(){
        RequestContext ctx = RequestContext.getCurrentContext();
        try {

            throw new RuntimeException("异常");
        }catch (Exception ex){
            ctx.set("error.status_code",HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            ctx.set("error.exception",ex);
            ctx.set("error.message",ex.getLocalizedMessage());
        }
        return ctx;
    }
}

它会抛出这样的异常:

{ 
"timestamp": 1513303905953, 
"status": 400, 
"error": "", 
"exception": "", 
"message": ""
}

status:对应error.status_code参数的值。

exception:对应error.exception参数中Exception的类型。

message:对应error.exception参数中Exception的message信息。

ErrorFilter处理

@Component
public class ErrorFilter extends ZuulFilter {

    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() throws ZuulException {
        RequestContext ctx=RequestContext.getCurrentContext();
        Throwable thrrowable=ctx.getThrowable();
        log.error("this is a ErrorFilter:{}",thrrowable.getCause().getMessage());
        ctx.set("error.status_code",HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        ctx.set("error.exception",thrrowable.getCause());
        ctx.set("error.message",thrrowable.getMessage());
        return null;
    }
}

然后在主类上添加这个bean

   @Bean
   public ErrorFilter errorFilter(){return new ErrorFilter();}

自定义异常信息

自定义异常只需要继承DefaultErrorAttributes类然后实现getErrorAttributes方法:

@Component
public class DidiErrorAttributes extends DefaultErrorAttributes {

    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
        Map<String, Object> result = super.getErrorAttributes(webRequest, includeStackTrace);
        result.put("a","aa");
        return result;
    }
}

通过这个方法就能自由的自定义错误返回信息。

禁用过滤器

在zuul中提供了一个参数来禁用指定的过滤器:

zuul.<SimpleClassName>.<filterType>.disable=true

如果想要禁用AccessFilter:

zuul.AccessFilter.pre.disable=true

:这样就能禁用AccessFilter过滤器了。

 

发布了194 篇原创文章 · 获赞 118 · 访问量 75万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览