目录
简介
Zuul是Netflix开源的微服务网关,主要功能是路由转发和过滤器,其原理也是一系列filters,这些filters可以帮我们实现以下功能:
- 身份验证和安全性
- 观察和监控
- 动态路由
- 负载均衡
- 静态响应处理
- 路由多样化
Zuul中的过滤器
Zuul一共有四种过滤器,分别是:
pre:在请求被路由之前调用,可利用这种过滤器鉴权。选择微服务,记录日志,限流。
route:在将请求路由到微服务调用,用于构建发送给微服务的请求,并用httpclinet ( 或者ribbon )请求微服务。
post:在调用微服务执行后。可用于添加header,记录日志,将响应发给客户端。
error:在其他阶段发生错误是,走此过滤器。
过滤器的执行流程
搭建Zuul
首先搭建Eureka服务,可以参考此链接搭建Eureka服务
新建Zuul服务,加入以下依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
修改application.yml文件,加入以下配置
server:
port: 8700
eureka:
client:
service-url:
# 向Eureka Server的注册地址,在集群情况下需要将注册地址打乱,不然压力都会在第一个地址的服务器下
defaultZone: http://localhost:8900/eureka
# 刷新注册表( 拉取注册表 )间隔,默认30秒
registry-fetch-interval-seconds: 5
instance:
# 心跳续约间隔
lease-renewal-interval-in-seconds: 10
# 心跳过期时间
lease-expiration-duration-in-seconds: 10
# 访问的路径变为IP地址
prefer-ip-address: true
zuul:
routes:
test:
path: /test/**
serviceId: demo-test-server
在启动类上加入@EnableZuulProxy注解,如下
@EnableZuulProxy
@SpringBootApplication
public class DemoZuulServerApplication {
public static void main(String[] args) {
SpringApplication.run(DemoZuulServerApplication.class, args);
}
}
完成搭建之后,启动Zuul服务查看Eureka中是否有Zuul服务的注册信息,如果有表示搭建成功
使用过滤器
route过滤器的默认三种配置
路由到服务
由RibbonRoutingFilter实现,以下配置表示当匹配到"/test/"路径的请求就转发到demo-test-server服务
zuul:
routes:
test:
path: /test/**
serviceId: demo-test-server
路由到url地址
由SimpleHostRoutingFilter实现,以下配置表示当拦截到"/test/csdn"请求时就转发到csdn去,可以在只知道请求路径不知道服务时使用
zuul:
routes:
test:
path: /test/csdn
url: https://www.csdn.net/
转发给自己
由SendForwardFilter实现,url要以forward:开头,表示该请求再次跳转到“/user”
routes:
test:
path: /test/**
url: forward: /user
自定义过滤器
自定义过滤器的使用场景非常广泛,如鉴权、安全认证、灰度发布等场景都可以通过自定义过滤器实现
@Configuration
public class TestFilter extends ZuulFilter {
@Override
public String filterType() {
// 设置过滤类型 FilterConstants.PRE_TYPE FilterConstants.ERROR_TYPE FilterConstants.ROUTE_TYPE FilterConstants.POST_TYPE
return null;
}
@Override
public int filterOrder() {
// 优先级 越小越优先执行
return 0;
}
@Override
public boolean shouldFilter() {
// 是否需要过滤,true为需要过滤,这里可以加相应的判断条件
return false;
}
@Override
public Object run() throws ZuulException {
// 具体要实现的业务逻辑
return null;
}
}
实战-限流拦截器
@Configuration
public class CurrentLimitFilter extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
/**
* 使用google的限流工具,1代表每秒1个
*/
private static final RateLimiter rl = RateLimiter.create(1);
@Override
public Object run() {
// 判断是否拿到令牌
if(!rl.tryAcquire()) {
RequestContext currentContext = RequestContext.getCurrentContext();
// 如果没拿到令牌,后面的过滤器都不执行
currentContext.setSendZuulResponse(false);
currentContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
}
return null;
}
}