API网关服务组件Spring Cloud Zuul使用详解9(过滤器详解1:基本用法)
十一、过滤器基本用法
1,基本介绍
(1)Spring Cloud Zuul 包含了对请求的路由和过滤这 2 个核心功能。路由功能负责将请求转发到具体的微服务上,而过滤器负责对请求的处理过程进行干预,是实现权限校验、服务聚合等功能的基础。
(2)在实际运行时,路由映射和请求转发是由几个不同的过滤器完成的。每一个进入 zuul 的 http 请求都会经过一系列的过滤器处理链得到请求响应并返回给客户端。
(3)Spring Cloud Zuul 包含 4 种类型的过滤器:
- pre 过滤器。在请求被路由之前调用。Zuul 请求微服务之前。比如请求身份验证,选择微服务实例,记录调试信息等。
- routing 过滤器。在路由请求时被调用,负责转发请求到微服务。原始请求在此构建,并使用 Apache HttpClient 或 Netflix Ribbon 发送原始请求。
- post 过滤器。在 route 和 error 过滤器之后被调用。可以在响应添加标准 HTTP Header、收集统计信息和指标,以及将响应发送给客户端等。
- error 过滤器。在处理请求发生错误时被调用。
2,使用样例
(1)下面代码定义了一个简单的 Zuul 过滤器,它实现了在请求被路由之前检查 HttpServletRequest 中是否有 accessToken 参数,若有就进行路由,若没有就拒绝访问,返回 401 Unauthorized 错误。
过滤器的实现十分简单,我们只需要继承 ZuulFilter 抽象类并实现它定义的 4 个抽象函数就可以了。这 4 个方法的作用如下:
- filterType:过滤器的类型,它决定过滤器在请求的哪个生命周期中执行。这里定义为 pre 代表会在请求被路由之前执行。其他几种过滤器(routing、post、error)的含义可以参考上方基本介绍。
- 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 错误。说明过滤器起作用了: