Spring Cloud学习笔记-009

API网关服务:Spring Cloud Zuul

  API网关是一个更为智能的应用服务器,它的定义类似于面向对象设计模式中的Facade模式,它的存在就像是整个微服务架构系统的门面一样,所有的外部客户端访问都需要经过它来进行调度和过滤。它除了要实现请求路由、负载均衡、校验过滤等功能之外,还需要更多能力,比如与服务治理框架的结合、请求转发时的熔断机制、服务的聚合等一系列高级功能。

  在Spring Cloud中提供了基于Netflix Zuul实现的API网关组件——Spring Cloud Zuul。

  首先,对于路由规则与服务实例的维护问题。Spring Cloud Zuul通过与Spring Cloud Eureka进行整合,将自身注册为Eureka服务治理下的应用,同时从Eureka中获得了所有其他微服务的实例信息。这样的设计非常巧妙地将服务治理体系中维护的实例信息利用起来,将维护服务实例的工作交给了服务治理框架自动完成,不再需要人工介入。而对于路由规则的维护,Zuul默认会将通过以服务名作为ContextPath的方式来创建路由映射,大部分情况下,这样的默认设置已经可以实现我们大部分的路由需求,除了一些特殊情况(比如兼容一些老的URL)还需要做一些特别的配置。但是相比于之前架构下的运维工作量,通过引入Spring Cloud Zuul实现API网关后,已经能够大大减少了。

  其次,对于类似签名校验、登录校验在微服务架构中冗余问题。理论上来说,这些校验逻辑在本质上与微服务应用自身的业务并没有多大的关系,所以它们完全可以独立成一个单独的服务存在,只是它们被剥离和独立出来之后,并不是给各个微服务调用,而是在API网关服务上进行统一调用来对微服务接口做前置过滤,以实现对微服务接口的拦截和校验。

1. 首先,搭建几个用于路由和过滤使用的微服务应用,可是使用之前的注册中心和demo-member、demo-customer-feign,分别启动三个应用。

2. 创建maven工程,骨架选择quickstart,命名为:demo-api-gateway。

3. 在pom.xml文件中引入相关依赖:

4. 创建启动类:

5. 在srcmain esources目录下创建application.yml文件:

6. 进入注册中心,观察启动的服务:

7. 在demo-api-gateway的pom.xml文件中添加Eureka依赖,并在application.yml文件中指定Eureka位置和进行路由的配置:

8. 启动demo-api-gateway服务,分别向网关发起下面请求:

  ◆http://localhost:5217/api-a/member:该url符合/api-a/**规则,由api-a路由负责转发,该路由映射的serviceId为member-service,所有最终/member请求会被发送到member-service服务的某个实例上去。

  ◆http://localhost:5217/api-b/getMember:该url符合/api-b/**规则,由api-b路由负责转发,该路由映射的serviceId为customer-service-feign,所有最终/getMember请求会被发送到customer-service-feign服务的某个实例上去。

  通过面向服务的路由配置方式,我们不需要再为各个路由维护微服务应用的具体实例的位置,而是通过简单的path与serviceId的映射组合,使得维护工作变得非常简单。这完全归功于Spring Cloud Eureka的服务发现机制,它使得API网关服务可以自动化完成服务实例清单的维护,完美地解决了对路由映射实例的维护问题。

请求过滤

  Zuul允许开发者在API网关上通过定义过滤器来实现对请求的拦截与过滤,只需要继承ZuulFilter抽象类并实现它定义的4个抽象方法就可以完成对请求的拦截和过滤了。

  下面实现一个简单的Zuul过滤器,它实现了再请求被路由之前检查HttpServletRequest中是否有token参数,若有就进行路由,若没有就拒绝访问,返回401 Unauthorized错误。

1. 定义AccessFilter类,集成ZuulFilter:

名词解释:

◆filterType:该方法需要返回一个字符串来代表过滤的类型,而这个类型就是在HTTP请求过程中定义的各个阶段。在Zuul中默认定义了4种不同的生命周期的过滤器类型:

  ■pre:可以在请求被路由之前调用。

  ■routing:在路由请求时被调用。

  ■post:在routing和error过滤器之后被调用。

  ■error:处理请求时发生错误时被调用。

◆filterOrder:通过int值来定义过滤器的执行顺序,数值越小优先级越高。

◆shouldFilter:返回一个boolea值来判断该过滤器是否要执行。可以通过此方法来指定过滤器的有效范围。

◆run:过滤器的具体逻辑,在该方法中,可以实现自定义的过滤逻辑,来确定是否要拦截当前的请求,不对其进行后续的路由,或是在请求路由返回结果之后,对处理结果做一些加工等。

2. 实现了自定义过滤器之后,并不会直接生效,还需要为其创建具体的Bean才能启动该过滤器,在启动类中添加如下内容:

3. 重启网关项目,并发起如下请求,对上述定义的过滤器做一个验证:

  ◆http://localhost:5217/api-a/member:返回401错误。

  ◆http://localhost:5217/api-a/member?token=123:正确路由到member-service的/member接口,并返回相应内容。

其他

  通过Eureka与Zuul的整合已经省去了维护服务实例清单的大量配置工作,剩下只需要再维护请求路径的匹配表达式与服务名的映射关系即可。但是在实际运用过程中会发现,大部分的路由配置规则几乎都会采用服务名作为外部请求的前缀,例如上述的member-seriver,而对应的服务名称也是member-service

  对于这样具有规则性的配置内容,我们总是希望可以自动化地完成。Zuul正好默认实现了这样的功能,当Spring Cloud Zuul构建API网关服务引入Spring Cloud Eureka之后,它为Eureka中的每个服务都自动创建一个默认路由规则,这些默认规则的path会使用serviceId配置的服务名作为请求前缀,如上述的路由配置规则,可以直接注释掉:

  重启网关服务,就可以使用服务名作为前缀进行服务的调用:

  对于版本的管理,当微服务有不同的版本的时候,例如memberservice-v1,当然可以通过微服务名称来区分不同的版本,从而调用各个版本的服务,但是这样生成出来的表达式规则较为单一,不利于通过路径规则来进行管理。通常的做法是为这些不同版本的微服务应用生成以版本代号作为路由前缀定义的路由规则,比如/v1/meberservie/。这时候,通过这样具有版本号前缀的URL路径,我们就可以很容易地通过路径表达式来归类和管理这些具有版本新的微服务了。

  具体操作方法是,首先停止member-service服务,并将其服务名称改为memberservice-v1,然后启动该服务。在网关服务的启动类中,添加如下代码:

  重新启动网关服务,在浏览器中访问测试:

网关总结

◆它作为系统的统一入口,屏蔽了系统内部各个微服务的细节。

◆它可以与服务治理框架结合,实现自动化的服务实例维护以及负载均衡的路由转发。

它可以实现接口权限校验与微服务业务逻辑的解耦。

◆通过服务网关中的过滤器,在各生命周期中去校验请求的内容,将原本在对外服务层做的校验前移,保证了微服务的无状态性,同时降低了微服务的测试难度,让服务本身更集中关注业务逻辑的处理。

原文地址:https://www.cnblogs.com/Oven5217/p/8849577.html