1. Zuul介绍
在整个Spring Cloud微服务框架里,Zuul扮演着”智能网关“的角色。一方面,Zuul是接入网关,起到反向代理的作用,是外部消费者请求内部服务的唯一入口。另一方面,Zuul也具备过滤功能,通过在运行时注入过滤规则可实现用户鉴权、动态路由、灰度发布、A/B测试、负载限流等功能。
Zuul的大部分功能都是通过过滤功能来完成的,Zuul可以提供四种标准类型的过滤,如下图所示:
1) Pre: 过滤规则在路由之前起作用。可以利用“Pre”过滤器实现用户鉴权,记录请求日志等;
2) Routing:过滤规则在路由时发生作用。可以利用“Routing”过滤器实现动态路由、灰度发布、A/B测试、负载限流等。
3) Post:过滤规则在路由之后发生作用。可以利用"Post"过滤器收集统计信息和指标,将微服务的相应写入Http响应并返回给服务消费者;
4) Error:过滤规则路由过程中发生错误时发生作用。可以利用Error过滤器记录错误日志,并对错误进行二次处理等。
在过滤器之间用RequestContext传递消息。RequestContext存储的内容包括路由目标地址、错误信息、请求信息、响应信息等。Zuul的过滤规则也可以用基于JVM的语言编写,包括Java、Python、Groovy等。
2. 代码实现及验证
本次代码实现模拟两个场景:对用户进行鉴权;拦截请求,并重导向到另一个网址
2.1新增一个zuul-service项目:过程同之前过程类似,只不过在依赖项里增加对zuul的依赖。
2.2接入网关的实现
1) 在主程序添加@EnableZuulProxy注解,该注解会把外部调用路由到合适的服务;
2) 配置网关项目的属性,端口设为2299。在配置文件里,如果不显式指定负载均衡路由的url或serviceId,负载均衡会将路径/{service}导向到Eureka上注册为{service}的服务,此时也需要使能zuul自身带的load balancer(ribbon)功能。比如:http://.../loadbalance-service/... 会由负载均衡自动到导向到Eureka上注册为loadbalance-service的服务。
也可以用下列两种方式的任何一种显式路径的方式指定负载均衡将导向的服务,zuul将路径自动设为/cars,2288为负载均衡器ribbon的端口, loadbalance-service为负载均衡的应用名称
#zuul.routes.cars.url=http://localhost:2288
#zuul.routes.cars.serviceId=loadbalance-service
当指定url时,可以关闭zuul的load balancer功能;当使用serviceId时,需要使能zuul自身带的load balancer(ribbon)功能
#ribbon.eureka.enabled=false
具体配置如下所示:
3) 验证
在启动网关服务之前,先依次启动eureka server,bookingcar-service,loadbalance-service。其中bookingcar-service启动两个实例,端口号分别为2227和2228。
启动网关服务后,我们在Eureka界面可以看到BOOKINGCAR-SERVICE, LOADBALANCE-SERVICE,GATEWAY-SERVICE都已经启动。注意:服务注册到eureka上后,名称都变成了大写。
点击GATEWAY-SERVICE后面的链接,进入网关服务界面,输入“loadbalance-service/v1/lb/testport?name=bookingcar-service“,我们发现同负载均衡时的结果一样,这说明网关服务已起作用,网关自动连接到负载均衡服务loadbalance-service。
我们也可以通过在配置文件里制定serviceid的方式来使用网关。在配置文件里,取消对serviceId的注解,关闭网关服务后再次启动,我们发现“loadbalance-service/v1/lb/testport?name=bookingcar-service“与“cars/v1/lb/testport?name=bookingcar-service“同样起作用
Loadbalance-service:
Cars:
2.3 用户鉴权的实现
如前所述,用户鉴权一般利用前置过滤器实现。
1)新增一个新的类BookingCarPreFilter,该类继承自ZuulFilter。在BookingCarPreFilter的实现中,要重写虚拟函数filterType, filterOrder, run,shouldFilter。
前置过滤器的filterType为PRE_TYPE,filterOrder本次演示使用DEBUG_FILTER_ORDER,在shouldFilter里要判断是否要进行过滤,本次演示直接返回true,要进行过滤。
在run函数里进行具体的过滤。本次演示主要对用户进行鉴权。Run函数的具体实现如下:
2)验证
继续使用“http://cpx-bkdhx46cy4h.dir.svc.accenture.com:2299/loadbalance-service/v1/lb/testport?name=bookingcar-service“,我们发现响应已经变为:user id cann't be null。
在后面添加userid的参数,如http://cpx-bkdhx46cy4h.dir.svc.accenture.com:2299/loadbalance-service/v1/lb/testport?name=bookingcar-service&userid=88,响应恢复为正常
2.4 拦截请求的实现
在routing过滤器里,实现对请求的拦截,并重导向到一个新的网站,比如:www.sina.com.cn
1)新增一个新的类BookingCarRoutingFilter,该类继承自ZuulFilter。在BookingCarRoutingFilter的实现中,要重写虚拟函数filterType, filterOrder, run,shouldFilter。
前置过滤器的filterType为ROUTE_TYPE,filterOrder本次演示使用DEBUG_FILTER_ORDER,在shouldFilter里要判断是否要进行过滤,本次演示直接返回true,要进行过滤。
在run函数里进行具体的过滤。本次演示主要对请求进行拦截,并导向到一个新的网站。Run函数的具体实现如下:
2) 验证,使用“http://cpx-bkdhx46cy4h.dir.svc.accenture.com:2299/loadbalance-service/v1/lb/testport?name=bookingcar-service&userid=88“,页面跳转到外部网站,如下所示:
3. 总结
Zuul是智能网关,除了是外部请求的入口,更重要的是可以起到过滤作用。Netflix也在用Zuul实现A/B测试和金丝雀发布。
Zuul现在版本是2.0,基于Netty,对请求实现了异步处理与响应。
代码:https://github.com/shuxingliu/microservices
利用Spring Cloud实现微服务(四)- 微服务实现与注册
利用Spring Cloud实现微服务(三)- 业务领域驱动微服务设计