前言:本课程是在慕课网上学习Spring Cloud微服务实战 第9章 Zuul综合使用 时所做的笔记,供本人复习之用.
代码地址 https://github.com/springcloud-demo
目录
第一章 Pre与Post过滤器
下面是整个项目的架构图
可以看到所有的请求都要经过Zuul,然后才会到Service A,B,C.那么我们现在要对请求做一个权限的校验,假如没有A,B,C,我们都要对权限校验一次,比较麻烦,权限校验可以放在Zuul这里统一的进行校验,
1.1 实现Pre过滤器
写一个Filter实现ZuulFilter,重写四个方法.
第一个方法代表这个过滤器在哪一部分的过滤器,如果是在pre部分的过滤器,返回PRE_TYPE,如果是post部分的过滤器,返回PRE_POST,更多的类型可以见常量类FilterConstants.
第二个方法代表这个过滤器的优先级,数字越小,优先级越高,这里我们选择我们的过滤器作用在PRE_DECORATION_FILTER的前面,所以找到其所对应的顺序数字减一.更多的过滤器级别数字可以见FilterConstants.
第三个方法统一返回true.
第四个方法实现我们的过滤器的逻辑,通过RequestContext获取request请求,如果request的请求中有token字符串就放过,没有就设置请求失败,返回HttpStatus设置的401错误.
@Component
public class TokenFilter extends ZuulFilter {
//代表是pre,还是post
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER-1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
String token = request.getParameter("token");
if(StringUtils.isEmpty(token)){
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
}
return null;
}
}
结果:
请求 http://localhost:9000/myProduct/product/list?token=123 ,成功
请求 http://localhost:9000/myProduct/product/list ,失败,显示401错误.
1.2 实现Post过滤器
大体思路同上.
@Component
public class AddResponseHeaderFilter extends ZuulFilter {
@Override
public String filterType() {
return POST_TYPE;
}
@Override
public int filterOrder() {
return SEND_RESPONSE_FILTER_ORDER -1 ;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletResponse response = requestContext.getResponse();
response.setHeader("X-Foo", UUID.randomUUID().toString());
return null;
}
}
结果:
第二章 限流
由于Zuul充当的是API网关的角色,每个请求都会经过它,所以很适合在它上面对API做限流保护,防止网络攻击.比如某个API是发短信的,我们就要限制API的请求速率.在一定程度上抵御短信轰炸攻击,降低损失.
限流是放在前置过滤器中去做的,更现实一点说,是在请求被转发之前调用.如果前置过滤器有多个操作,限流应该放到最前面的地方,比如Zuul的前置过滤器里有限流,也有鉴权,那么限流应该早于鉴权,
限流的方案很多,有一种方案叫做令牌桶限流,会以一定的速率向桶中放入令牌,如果放满了就会丢弃掉,web请求过来会从令牌桶中获取到令牌,拿到令牌后才可以继续往下走,如果令牌都拿不到就会被拒绝.
2.1 代码实现
设置每秒钟向令牌桶里放入100个令牌,因为是限流,所以应该在所有过滤器的最前面,这通过设置Order为最小的Order数字减1,来设置优先级最高.最后过滤时的逻辑是,尝试获得令牌,如果获取不到令牌抛出异常.
@Component
public class RateLimitFilter extends ZuulFilter {
private static final RateLimiter RATE_LIMITER = RateLimiter.create(100);
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return SERVLET_DETECTION_FILTER_ORDER-1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object r