SpringCloud Netflix (七):API网关 Zuul
什么是API网关
API网关是对外服务的一个人口, 其隐藏了内部架构的实现, 是微服务架构中必不可 少的一个组件。API网关可以为我们管理大量的API接口, 还可以对接客户、适配协议、 进行安全认证、转发路由、限制流量、监控日志、防止爬虫、进行灰度发布等。
随着业务的发展,服务越来越多,前端用户如何调用微服务就成了一个难题。比如在线商城的产品详细信息UI可以显示关于产品的许多信息,例如,Amazon.com的商品详细信息页面显示:
-
关于这本书的基本信息,如书名、作者、价格等。
-
你买这本书的历史记录
-
其他经常和这本书一起买的东西
-
买这本书的顾客买的其他东西
-
客户评论
-
卖家排名 ......
这些信息都在不同的服务中,前端系统想要实现这么一个功能就需要和众多的服务进行交互,调用它们提供的接口,这样性能肯定是低的。而且前端系统的逻辑更复杂了,它需要 知道所有提供信息的微服务。这个时候API网关的作用就体现出来了, 通过API聚合内部 服务, 提供统一对外的API接口给前端系统, 屏蔽内部实现细节。
什么是Zuul
Zuul是从设备和网站到Netflix流媒体应用程序后端的所有请求的前门。作为一个边缘服务应用程序,Zuul被构建为支持动态路由、监视、弹性和安全性。它还可以根据需要将请求路由到多个Amazon自动伸缩组。
为什么要使用zuul
因为Netflix API流量的数量和多样性有时会导致生产问题迅速而毫无预警地出现,所以我们需要一个能让我们迅速改变这种行为的系统来应对这些情况。
Zuul使用了一系列不同类型的过滤器,使我们能够快速、灵活地将功能应用到我们的边缘服务。这些过滤器帮助我们执行以下功能:
-
身份验证和安全性 - 识别每个资源的身份验证要求,并拒绝不满足这些要求的请求。
-
洞察和监控 - 在服务边缘跟踪的有意义的数据并统计,以便为我们提供准确的生产视图。
-
动态路由 - 根据需要将请求动态路由到不同的后端集群。
-
压力测试 - 逐渐增加对集群的流量以评估性能。
-
自动卸载 - 为每种类型的请求分配容量,并弃用超过限制的请求。
-
静态响应处理 - 直接在边缘构建一些响应,而不是将它们转发到内部集群
-
多区域弹性 - 跨越AWS区域进行请求路由,以使ELB(弹性负载均衡)更加多样化,并使边缘位置与使用者尽可能接近
( Zuul代码结构)
Zuul路由功能
Zuul提供了一套简单且强大路由配置策略,利用路由配置我们可以完成对微服务和URL更精确的控制。
1创建springcloud-zuul-9001模块,并导入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> <version>1.4.7.RELEASE</version> </dependency> <!--zuul需要注册到注册中心中,所以需要导入eureka-client依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>1.4.6.RELEASE</version> </dependency>
2.添加配置
server:
port: 9001
spring:
application:
name: gateway-zuul
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
instance:
prefer-ip-address: true
3.在启动类上添加注解@EnableZuulProxy
, 允许Zuul代理
@SpringBootApplication @EnableZuulProxy public class GatewayZuul { public static void main(String[] args) { SpringApplication.run(GatewayZuul.class, args); } }
启动 springcloud-eureka-7001、springcloud-provider-8888 和 springcloud-zuul-9001,访问 localhost:9001/springcloud-provider/user/1 zuul就会路由到 localhost:8888/user/1,即可获得springcloud-provider返回的结果。
如果报APPLICATION FAILED TO START
异常,请把spring-boot-starter-parent版本降到2.0.5.RELEASE即可
4.路由配置
虽然我们把应用服务的ip和端口隐藏了起来,但是却把服务名给暴露出来,这是不安全的,所以需要在配置里重写指定微服务的访问地址,用 /provider 代替 /springcloud-provider
zuul:
routes:
springcloud-provider: /provider/**
这时候访问localhost:9001/provider/user/1即可获取结果,但是当我们访问localhost:9001/springcloud-provider/user/1还是可以正常访问,获取结果,所以我们要在配置里忽略掉服务名
zuul: ignored-services: springcloud-provider #使用 "*" 可以忽略所有服务名 routes: springcloud-provider: /provider/**
我们还可以为访问路径添加前缀,例如为路径添加/springcloud前缀,添加完后就只能通过localhost:9001/springcloud/provider/user/1路径访问
zuul: prefix: /springcloud ignored-services: springcloud-provider routes: springcloud-provider: /provider/**
Zuul过滤器
过滤器是Zuul功能的核心。他们负责应用程序的业务逻辑,执行各种任务。
Type:通常在应用过滤器时定义路由期间过程的阶段(尽管它可以是任何自定义字符串)
Async:定义过滤器是sync还是Async,通常意味着您需要进行外部调用还是只在内部上工作
Execution Order:应用于类型中,定义跨多个过滤器的执行顺序
Criteria:执行过滤器所需的条件
Action:满足条件时要执行的操作
Zuul提供了一个动态读取、编译和运行这些过滤器的框架。过滤器不直接相互通信,而是通过对每个请求唯一的RequestContext共享状态。
尽管Zuul支持任何基于JVM的语言,但过滤器目前是用Groovy编写的。每个过滤器的源代码都会写入Zuul服务器上的指定目录集,这些目录会定期轮询检查是否有更新。Zuul会从磁盘读取更新的过滤器,动态编译到正在运行的服务器中,并由Zuul为每个后续请求调用。
过滤器类型
通过com.netflix.zuul
包下的FilterProcessor类可以知道Zuul过滤器有4个基本类型:
-
pre:在请求路由到目标之前执行。一般用于请求认证、负载均衡和日志记录。
-
route:处理目标请求。这里使用Apache HttpClient或Netflix Ribbon构造对目标的HTTP请求。
-
post:在目标请求返回后执行。一般会在此步骤添加响应头、收集统计和性能数据等。
-
error:整个流程某块出错时执行。
( Zuul请求生命周期 )
自定义过滤器
1.创建自定义Zuul过滤器PreRequestLogFilter
public class PreRequestLogFilter extends ZuulFilter { @Override public String filterType() { //过滤器类型 return "pre"; } @Override public int filterOrder() { //过滤器优先级 return 0; } @Override public boolean shouldFilter() { //是否启用该过滤器 return true; } @Override public Object run() throws ZuulException { //过滤器运行方法 RequestContext currentContext = RequestContext.getCurrentContext(); HttpServletRequest request = currentContext.getRequest(); System.out.println(String.format("send %s request to %s",request.getMethod(),request.getRequestURL())); return null; } }
2.在启动类添加配置,将该过滤器注入到应用中
@SpringBootApplication @EnableZuulProxy public class GatewayZuul { public static void main(String[] args) { SpringApplication.run(GatewayZuul.class, args); } @Bean public PreRequestLogFilter preRequestLogFilter(){ //将该过滤器注入到应用中 return new PreRequestLogFilter(); } }
我们可以在更改过滤器的shouldFilter()
方法来启用或关闭过滤器,也可以通过application配置来启用或关闭
zuul: PreRequestLogFilter: #过滤器名 pre: #过滤器类型 disable: true