介绍
Zuul是Netflix开源的微服务网关,它可以和Eureka、Ribbon、Hystrix等组件配合使用,Zuul组件核心是一系列过滤器,这些过滤器可以完成:
- 动态路由:动态将请求路由到不同后端集群
- 压力测试:逐渐增加指向集群的流量,以了解性能
- 负载分配:为每一种负载类型分配对应的容量,并弃用超出限定值的请求
- 静态相应处理:边缘位置进行响应,避免转发到内部集群
- 身份认证和安全:识别每个一资源的验证要求,并拒绝那些不符合的请求。Spring Cloud对Zuul进行了整合和增强
搭建Zuul网关服务器
- 创建一个新的maven工程,引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
- 配置yml
server:
port: 8888 #端口
spring:
application:
name: api-zuul-service #服务名称
- 启动类
@SpringBootApplication
//开启Zuul网关功能
@EnableZuulProxy
public class ZuulServerApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulServerApplication.class,args);
}
}
路由
路由:根据请求的url将请求分配到对应的微服务中进行处理。
- 基础路由配置
#路由配置
zuul:
routes:
#例子
product-service: #路由id
path: /product-service/** #映射路径 #localhost:8888/product-service/xxxxx
url: http://192.168.0.107:9001/ #映射路径对应的实际地址
访问:http://127.0.0.1:8888/product-service/product/getProduct/1
- 面向服务的路由配置(整合Eureka)
1.添加Eureka的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.开启Eureka的客户端服务发现
//在启动类上添加注解(比较新的版本可以不加)
@EnableDiscoveryClient
3.在Zuul网关服务中配置Eureka的注册中心相关信息
添加eureka配置
#eureka配置
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka/,http://localhost:8999/eureka/
instance:
prefer-ip-address: true #使用ip地址注册
instance-id: ${spring.cloud.client.ip-address}:${server.port} #向注册中心中注册ip
4.修改路由中的映射配置
#路由配置
zuul:
routes:
#例子
product-service: #路由id
path: /product-service/** #映射路径 #localhost:8888/product-service/xxxxx
# url: http://192.168.0.107:9001/ #映射路径对应的实际地址
serviceId: product-service #配置转发的微服务的服务名称
- 简化路由配置
#路由配置
zuul:
routes:
#如果当前的微服务名称product-service,默认的请求映射路径 /product-service/**
# 如果路由id和对应的微服务的serviceId一致的话
product-service: /product-service/**
其实不配置也可以,比如,现在配置文件上没有配置comsumer-service,但是如果直接访问:http://127.0.0.1:8888/consumer-service/demo/get/1,也是完全没问题的。
过滤器
Zuul中的过滤器跟我们使用的javax.servlet.Filter不一样,javax.servlet.Filter只有一种类型,可以通过配置urlPatterns来拦截对应的请求。而Zuul中的过滤器一共就4种类型,而且每一种类型都有对应的使用场景:
- PRE:这种过滤器在请求被路由之前调用。我们可以利用这种过滤器实现身份验证、在集权中选择请求的微服务、记录调试信息等。
- ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或者Netfilx Ribbon请求微服务。
- POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
- ERROR:在其他阶段发生错误时执行该过滤器。
调用顺序示意图:
自定义zuulFilter
1.继承ZuulFilter ,实现四个方法
2.将LoginFilter 交给spring容器管理
/**
* 自定义的zuul过滤器
* 继承抽象父类
* */
@Component
public class LoginFilter extends ZuulFilter {
/**
* 定义过滤器类型
* pre
* routing
* post
* error
* */
@Override
public String filterType() {
return "pre";
}
/**
* 指定过滤器的执行顺序
* 返回值越小,执行顺序越高
* */
@Override
public int filterOrder() {
return 1;
}
/**
* 当前过滤气是否生效
* true:使用
* false:不适用
* */
@Override
public boolean shouldFilter() {
return true;
}
/**
* 执行过滤器中的业务逻辑
* */
@Override
public Object run() throws ZuulException {
System.out.println("执行了过滤器");
return null;
}
}
身份认证示例
重写run方法
/**
* 执行过滤器中的业务逻辑
* 身份认证:
* 1.所有的请求需要携带一个参数:access-token
* 2.获取request请求
* 3.通过request获取参数access-token
* 4.判断token是否为空
* 4.1 token == null:身份验证失败
* 4.2 token != null:执行后续操作
* */
@Override
public Object run() throws ZuulException {
//1.获取zuul提供的上下文对象RequestContext
RequestContext ctx = RequestContext.getCurrentContext();
//2.从RequestContext中获取request
HttpServletRequest request = ctx.getRequest();
//3.获取请求参数access-token
String token = request.getParameter("access-token");
//4.判断
if(token == null){
ctx.setSendZuulResponse(false);//拦截请求
ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
}
//继续执行
return null;
}
Zuul原理
弊端
1.请求线程池同步阻塞问题
2.不支持WebSoucket