5.3 Zuul过滤
1.简介
Zuul的大部分功能都是通过过滤功能来完成的,Zuul可以提供四种标准类型的过滤,如下图所示:
-
Pre: 过滤规则在路由之前起作用。可以利用“Pre”过滤器实现用户鉴权,记录请求日志等;
-
Routing:过滤规则在路由时发生作用。可以利用“Routing”过滤器实现动态路由、灰度发布、A/B测试、负载限流等。
-
Post:过滤规则在路由之后发生作用。可以利用"Post"过滤器收集统计信息和指标,将微服务的相应写入Http响应并返回给服务消费者;
-
Error:过滤规则路由过程中发生错误时发生作用。可以利用Error过滤器记录错误日志,并对错误进行二次处理等。
总结:在过滤器之间用RequestContext传递消息。RequestContext存储的内容包括路由目标地址、错误信息、请求信息、响应信息等。Zuul的过滤规则也可以用基于JVM的语言编写,包括Java、Python、Groovy等。
2. 使用过滤功能
在Zuul中使用过滤器,只需要继承ZuulFilter抽象类实现其定义的四个抽象函数就可对请求进行拦截与过滤。
①:创建一个实现类:
<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="java" cid="n317" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); --select-text-bg-color: #36284e; --select-text-font-color: #fff; font-size: 0.9rem; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 3em; margin-left: 2em; padding-left: 0px; padding-right: 1ch; width: inherit; color: rgb(31, 9, 9); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> public class ExampleFilter extends ZuulFilter{
/*
- Zuul过滤器需要实现四个函数;filterType:代表过滤器类型;filterOrder:执行顺序;
- shouldFilter:是否启动过滤器;run:过滤器的逻辑
- */
private static Logger logger = LoggerFactory.getLogger(ExampleFilter.class);
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
logger.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString()));
Object accessToken = request.getParameter("accessToken");
if(accessToken == null) {
logger.warn("access token is empty");
context.setSendZuulResponse(false);
//context.setResponseStatusCode(401);
context.setResponseBody("This is 401 error!");
return null;
}
logger.info("It's access token ok");
return null;
}
}</pre>
在使用过滤器时,只需要实现其中的四个函数即可:
filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型。
filterOrder:通过int值来定义过滤器的执行顺序。
shouldFilter:返回一个boolean类型来判断该过滤器是否要执行,所以通过此函数可实现过滤器的开关。
run:过滤器的具体逻辑。
注,通过ctx.setSendZuulResponse(false)令zuul过滤该请求,不对其进行路由,然后通过ctx.setResponseStatusCode(401)设置了其返回的错误码,当然我们也可以进一步优化我们的返回,比如,通过ctx.setResponseBody(body)对返回body内容进行编辑等。
②:实例化过滤器(在主类中):
1564926554673③:测试过滤器是否起到作用:
访问路径1:http://localhost:8523/api-a/add?a=1&b=2
结果1:由于没有传参accessToken,此时会返回一个错误消息。
image访问路径2:http://localhost:8523/api-a/add?a=1&b=2&accessToken=token
结果2:此时会返回一个计算结果。
image对应的控制台页打印出相关信息:
image注:由于服务路由Zuul中也包含了断路器的功能,所以即使某台服务器发生故障,也不会影响整体服务之间的关联和运行。
测试:关闭discovery服务器,此时通过路由的映射关系去访问其对应的路径,则会弹出错误提示:
image5.4 总结
对于微服务架构中,服务路由是必不可缺的一部分,主要有以下几点体现:
-
不仅仅实现了路由功能来屏蔽诸多服务细节,更实现了服务级别、均衡负载的路由。
-
实现了接口权限校验与微服务业务逻辑的解耦。通过服务网关中的过滤器,在各生命周期中去校验请求的内容,将原本在对外服务层做的校验前移,保证了微服务的无状态性,同时降低了微服务的测试难度,让服务本身更集中关注业务逻辑的处理。
-
实现了断路器,不会因为具体微服务的故障而导致服务网关的阻塞,依然可以对外服务。
网友评论