当前位置: > > > API网关服务组件Spring Cloud Zuul使用详解9(过滤器详解1:基本用法)

API网关服务组件Spring Cloud Zuul使用详解9(过滤器详解1:基本用法)

十一、过滤器基本用法

1,基本介绍

(1)Spring Cloud Zuul 包含了对请求的路由和过滤这 2 个核心功能。路由功能负责将请求转发到具体的微服务上,而过滤器负责对请求的处理过程进行干预,是实现权限校验、服务聚合等功能的基础。
(2)在实际运行时,路由映射和请求转发是由几个不同的过滤器完成的。每一个进入 zuul http 请求都会经过一系列的过滤器处理链得到请求响应并返回给客户端。
(3)Spring Cloud Zuul 包含 4 种类型的过滤器:
  • pre 过滤器。在请求被路由之前调用。Zuul 请求微服务之前。比如请求身份验证,选择微服务实例,记录调试信息等。
  • routing 过滤器。在路由请求时被调用,负责转发请求到微服务。原始请求在此构建,并使用 Apache HttpClientNetflix Ribbon 发送原始请求。
  • post 过滤器。在 route error 过滤器之后被调用。可以在响应添加标准 HTTP Header、收集统计信息和指标,以及将响应发送给客户端等。
  • error 过滤器。在处理请求发生错误时被调用。

2,使用样例

(1)下面代码定义了一个简单的 Zuul 过滤器,它实现了在请求被路由之前检查 HttpServletRequest 中是否有 accessToken 参数,若有就进行路由,若没有就拒绝访问,返回 401 Unauthorized 错误。
过滤器的实现十分简单,我们只需要继承 ZuulFilter 抽象类并实现它定义的 4 个抽象函数就可以了。这 4 个方法的作用如下:
  • filterType:过滤器的类型,它决定过滤器在请求的哪个生命周期中执行。这里定义为 pre 代表会在请求被路由之前执行。其他几种过滤器(routingposterror)的含义可以参考上方基本介绍。
  • filterOrder:过滤器的执行顺序。当请求在一个阶段中存在多个过滤器时,需要根据该方法返回的值来依次执行(数字越小优先级越高)。
  • shouldFilter:判断该过滤器是否需要被执行。这里我们直接返回了 true,因此该过滤器会对所有请求都会生效。实际运用用中我们可以利用该函数来指定过滤器的有效范围。
  • run:过滤器的具体逻辑。在该函数中,我们可以实现自定义的过滤逻辑,来确定是否拦截当前的请求,不对其进行后续的路由,或是在请求路由返回结果之后,对处理结果做一些加工。
@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() {
        //是否执行该过滤器,true代表需要过滤
        return true;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();

        log.info("send {} request to {}", request.getMethod(), request.getRequestURL().toString());

        //获取传来的参数accessToken
        Object accessToken = request.getParameter("accessToken");
        if(accessToken == null) {
            log.warn("access token is empty");
            //过滤该请求,不往下级服务去转发请求,到此结束
            ctx.setSendZuulResponse(false);
            //设置返回的错误码
            ctx.setResponseStatusCode(401);
            //设置返回的内容
            ctx.setResponseBody("{\"result\":\"accessToken为空!\"}");
            ctx.getResponse().setContentType("text/html;charset=UTF-8");
            return null;
        }
        //如果有token,则进行路由转发
        log.info("access token ok");
        //这里return的值没有意义,zuul框架没有使用该返回值
        return null;
    }
}

(2)启动网关服务测试一下,首先发起 http://localhost:5555/hello-service/hello?accessToken=123 请求。由于请求中带有 accessToken 参数,因此可以正确路由到 hello-service /hello 接口。

(3)如果我们把 accessToken 参数去掉,则会返回 401 错误。说明过滤器起作用了:
评论0