【微服务网关SpringCloudGateway】
主要内容
- API网关
- Spring Cloud Gateway简介
- Spring Cloud Gateway路由
- Spring Cloud Gateway谓词
- Spring Cloud Gateway过滤器
- Spring Cloud Gateway熔断
一、API网关
1. 什么是API网关
API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:
客户端会多次请求不同的微服务,增加了客户端的复杂性。
存在跨域请求,在一定场景下处理相对复杂。
认证复杂,每个服务都需要独立认证。
难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施。
某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难。
以上这些问题可以借助 API 网关解决。API 网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 API 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 API 网关来做,这样既提高业务灵活性又不缺安全性。
使用API网关后示意图:
使用 API 网关后的优点如下:
易于监控。可以在网关收集监控数据并将其推送到外部系统进行分析。
易于认证。可以在网关上进行认证,然后再将请求转发到后端的微服务,而无须在每个微服务中进行认证。
统一接入。减少了客户端与各个微服务之间的交互次数。
1.1 路由
路由是网关最基础的部分,路由信息有一个ID、一个目的URL、一组断言和一组Filter组成。如果断言路由为真,则说明请求的URL和配置匹配。
1.2 过滤器
网关非常重要的功能就是过滤器。可以把微服务中很多公共的功能都提出到网关的过滤器中,这样就可以实现复用。如:认证功能、权限校验功能等。
由于网关是统一的入口,所以还可以在网关中实现一些记录或容错等逻辑实现。例如限流、监控、熔断、协议转换、日志等。
一个标准的Spring webFilter。Spring cloud gateway中的filter分为两种类型的Filter,分别是Gateway Filter和Global Filter。过滤器Filter将会对请求和响应进行修改处理。
2. Spring Cloud中提供的网关解决方案
2.1 Spring Cloud Netflix Zuul
属于Spring Cloud Netflix下一个组件,具有灵活、简单的特点。在早期Spring Cloud中使用的比较多。
其版本更新都依赖于Netflix Zuul。
2.2 Spring Cloud Gateway
由Spring 自己推出的网关产品,完全依赖Spring自家产品。符合Spring战略意义,其更新版本等都由Spring自己把控。
目前很多项目中都是使用Gateway替代Zuul。
在本套课程中讲解的也是Gateway
二、Spring Cloud Gateway
1. 简介
Spring cloud gateway是spring官方基于Spring 5.0、Spring Boot2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供简单、有效和统一的API路由管理方式,Spring Cloud Gateway作为Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,其不仅提供统一的路由方式,并且还基于Filer链的方式提供了网关基本的功能,例如:安全、监控/埋点、限流等。
2. 名词解释
2.1 Route
Route中文称为路由,Gateway里面的Route是主要学习内容。
一个路由包含ID、URI、Predicate集合、Filter集合。
在Route中ID是自定的,URI就是一个地址。剩下的Predicate和Filter学习明白了,Route就学习清楚了。
2.2 Predicate
中文:谓词。
谓词时学习Gateway比较重要的一点,简单点理解谓词就是一些附加条件和内容。
2.3 Filter
所有生效的Filter都是GatewayFilter的实例。在Gateway运行过程中Filter负责在代理服务“之前”或“之后”去做一些事情。
3. 流程
3.1 解释
当Gateway接收到外界请求后,如果Gateway Handler Mapping确认请求与路由匹配(Gateway可以包含多个Route),交给Gateway Web Handler 。之后交给特定的Filter 链进行处理,整个Filter 链的前置(pre)被执行后,执行代理的服务(Proxied Service),最后执行Filter 链的post部分。返回给Gateway Web Handler,在返回给Gateway Web Handler Mapping,最终返回给客户端。
三、使用Spring Cloud Gateway实现路由功能
1. 入门案例
Gateway网关,在默认环境下,可以通过服务名称实现网关路由功能。如:
现有微服务 - 服务名为: feign-app-service, 启动gateway网关后,请求地址为: http://gatewayIP:gatewayPort/feign-app-service/index, 可以实现访问feign-app-service微服务的/index控制器方法。
1.1 创建Gateway项目
1)POM文件
<?xml version="1.0" encoding="UTF-8"?>
2)配置文件
server:
port: 9000
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true # 开启Gateway服务注册和发现的功能
lower-case-service-id: true # 将请求路径上的服务名配置为小写
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
3)启动类
package
2. 配置文件手工绑定路由规则
2.1 POM文件
不需要修改。
2.2 配置文件
server:
port: 9000
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: false # 开启Gateway自动服务注册和发现的功能
lower-case-service-id: true # 将请求路径上的服务名配置为小写
routes:
- id: openfeign-client # 唯一命名,不重复即可,无其他要求
uri: lb://openfeign-client # 转发路径,lb代表loadbalance,即从Eureka中获取的服务列表负载均衡器。 openfeign-client即服务名称,相当于http://localhost:8082/
predicates: # 定义映射
- Path=/client/** # 发送到Gateway网关上的请求路径映射,此映射匹配的路径都会转发到uri上。 具体地址为: lb://openfeign-client/client/**
filters:
- StripPrefix=1 # 请求转发时,会自动过滤请求转发的第一节地址,即client。最终地址为: lb://openfeign-client/**
- id: openfeign-service
uri: lb://openfeign-service
predicates:
- Path=/service/**
filters:
- StripPrefix=1
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
2.3 启动类
不需要修改。
四、Predicate谓词
谓词:当满足条件在进行路由转发。
在Spring Cloud Gateway中谓词实现GatewayPredicate接口。其中类名符合:XXXRoutePredicateFactory,其中XXX就是在配置文件中谓词名称。在上面示例中Path=/demo/** 实际上使用的就是PathRoutePredicateFactory
所有的谓词都设置在predicates属性中,当设置多个谓词时取逻辑与条件,且一个谓词只能设置一组条件,如果需要有个多条件,添加多个相同谓词。
所有的Predicate都可以通过源码查看属性赋值的方式。查看方式为:
看类型中的Config内部类,
如:PathRoutPredicateFactory中
根据内部类的属性,来确认赋值数据的方式。如:PathRoutePredicateFactory中内部类Config的属性是List<String>类型的,那么赋值的时候,就是Path=a,b,c,d,使用逗号分隔多个值即可。
如:QueryRoutePredicateFactory中
有多个属性,param和regexp,都是字符串类型的。那么赋值的时候,必须是:Query=param属性的值[,regexp属性的值],因为属性param上有注解NotEmpty,代表此属性必须赋值,regexp属性没有这个赋值,则可选赋值。
1 Query
1.1 设置必须包含的参数名。
下面两种写法等效。都表示路径满足/demo/**同时包含参数abc。
Path和Query是谓词。abc是请求参数名称。
在浏览器中输入:http://localhost:9000/demo/one?abc=jqk
1.2 设置参数的值
abc请求参数名称。jqk. 是abc的值,是一个正则表达式。在正则表达式中点(.)表示匹配任意一个字符。所以当请求参数abc=jqka或abc=jqkw能满足谓词条件。
在谓词中赋值使用逗号(,)赋值因为Query后面已经有等号,在值内容中在出现等号语法说不过去了。
2. Header
表示请求头中必须包含的内容。
注意:
参数名和参数值之间依然使用逗号
参数值要使用正则表达式
如果Header只有一个值表示请求头中必须包含的参数。如果有两个值,第一个表示请求头必须包含的参数名,第二个表示请求头参数对应值。
如果设定请求头中需要包含多个参数及值。设置多个Header。在此处演示多个相同谓词配置,其他谓词中就不在强调可以配置多个谓词。
3. Method
Method表示请求方式。支持多个值,使用逗号分隔,多个值之间为or条件。
4. RemoteAddr
允许访问的客户端地址。
要注意使用127.0.0.1而不要使用localhost。
5. Weight
负载均衡中权重。同一个组中URI进行负载均衡。
语法:Weight=组名,负载均衡权重
在Eureka中注册两个服务,这个服务(项目)是相同的,应用程序名分别叫做demo-one和demo-two。
Gateway在路由匹配时demo-one将占20%,demo-two将占80%
6. Host
匹配请求参数中Host参数的值。满足Ant模式(之前在Spring Security中学习过)可以使用
? 匹配一个字符
* 匹配0个或多个字符
** 匹配0个或多个目录
7. Cookie
要求请求中包含指定Cookie名和满足特定正则要求的值。
Cookie必须有两个值,第一个Cookie包含的参数名,第二个表示参数对应的值,正则表达式。不支持一个参数写法。
8. Between
请求时必须在设定的时间范围内容,才进行路由转发。
注意:时间的格式
9. Before
在指定时间点之前
10. After
在指定时间点之后
五、使用Spring Cloud Gateway实现过滤器功能
Spring Cloud Gateway的filter分为两种:GatewayFilter和GlobalFilter。GlobalFilter会应用到所有的路由上,而Gatewayfilter将应用到单个路由或者一个分组的路由上。
多个过滤器会根据配置文件中的定义来决定执行顺序。
如果提供的自定义过滤器实现了Ordered接口,则可以通过接口中的方法getOrder来决定执行顺序。具体顺序由getOrder方法返回结果升序排列。
1. Spring Cloud Gateway内置过滤器
GatewayFilter是一个接口,通过查看源码,其有很多实现类,不同的实现类实现不同的过滤功能。具体如下:
常用过滤器有:
- ① AddRequestParameterGatewayFilterFactory - 在指定请求中增加请求参数的过滤器。
- ② AddRequestHeaderGatewayFilterFactory - 在指定请求中增加请求头参数的过滤器。
- ③ StripPrefixGatewayFilterFactory - 在指定请求中处理路径前缀的过滤器。
在Gateway中使用过滤器的方式非常简单,只要在配置文件中通过过滤器命名前缀即可快速使用,如使用AddRequestParameterGatewayFilterFactory,可以通过AddRequestParameter在配置文件中配置使用;如使用StripPrefixGatewayFilterFactory,可以通过StripPrefix在配置文件中配置使用。
具体配置过程如下:
server:
port: 9000
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: false # 开启Gateway自动服务注册和发现的功能
lower-case-service-id: true # 将请求路径上的服务名配置为小写
routes:
- id: openfeign-client # 唯一命名
uri: lb://openfeign-client # 转发路径,lb代表loadbalance,即从Eureka中获取的服务列表负载均衡器。 openfeign-client即服务名称,相当于http://localhost:8082/
predicates: # 定义映射
- Path=/client/** # 发送到Gateway网关上的请求路径映射,此映射匹配的路径都会转发到uri上。 具体地址为: lb://openfeign-client/client/**
filters:
- StripPrefix=1 # 请求转发时,会自动过滤请求转发的第一节地址,即client。最终地址为: lb://openfeign-client/**
- AddRequestParameter=id, 0 # 在请求中自动增加一个请求参数,参数名为id,参数值为0。可以用于提供固定参数。
- AddRequestParameter=name, testFilter # 每个AddRequestParameter过滤器,只能提供一个请求参数,提供多请求参数,需要定义多个过滤器。
- AddRequestHeader=my-header, test-header-value # 在请求中自动增加一个请求头参数,参数名为my-header,参数值为test-header-value。
- id: openfeign-service
uri: lb://openfeign-service
predicates:
- Path=/service/**
filters:
- StripPrefix=1
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
2 自定义过滤器
2.1 自定义GatewayFilter - 网关过滤器
1) 自定义过滤器
package
2)配置文件
server:
port: 9000
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: false # 开启Gateway自动服务注册和发现的功能
lower-case-service-id: true # 将请求路径上的服务名配置为小写
routes:
- id: openfeign-client # 唯一命名
uri: lb://openfeign-client # 转发路径,lb代表loadbalance,即从Eureka中获取的服务列表负载均衡器。 openfeign-client即服务名称,相当于http://localhost:8082/
predicates: # 定义映射
- Path=/client/** # 发送到Gateway网关上的请求路径映射,此映射匹配的路径都会转发到uri上。 具体地址为: lb://openfeign-client/client/**
filters:
- StripPrefix=1 # 请求转发时,会自动过滤请求转发的第一节地址,即client。最终地址为: lb://openfeign-client/**
- AddRequestParameter=id, 0 # 在请求中自动增加一个请求参数,参数名为id,参数值为0。可以用于提供固定参数。
- AddRequestParameter=name, testFilter # 每个AddRequestParameter过滤器,只能提供一个请求参数,提供多请求参数,需要定义多个过滤器。
- AddRequestHeader=my-header, test-header-value # 在请求中自动增加一个请求头参数,参数名为my-header,参数值为test-header-value。
- Authentication=token
- id: openfeign-service
uri: lb://openfeign-service
predicates:
- Path=/service/**
filters:
- StripPrefix=1
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
2.2 自定义GlobalFilter - 全局过滤器
GlobalFilter:全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器,它为请求业务以及路由的URI转换为真实业务服务的请求地址的核心过滤器,不需要配置,系统初始化时加载,并作用在每个路由上。
全局过滤器无需创建工厂类,也无需在配置文件中进行注册。因为其对所有的网关代理的路径都生效。
1) 自定义过滤器
package
六、使用Spring Cloud Gateway实现熔断功能
Spring Cloud Gateway也可以利用Hystrix的熔断特性,在流量过大时进行服务降级。
1. POM依赖
<?xml version="1.0" encoding="UTF-8"?>
2. 熔断处理代码
package
3. 配置文件
server:
port: 9000
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: false # 开启Gateway自动服务注册和发现的功能
lower-case-service-id: true # 将请求路径上的服务名配置为小写
routes:
- id: openfeign-client # 唯一命名
uri: lb://openfeign-client # 转发路径,lb代表loadbalance,即从Eureka中获取的服务列表负载均衡器。 openfeign-client即服务名称,相当于http://localhost:8082/
predicates: # 定义映射
- Path=/client/** # 发送到Gateway网关上的请求路径映射,此映射匹配的路径都会转发到uri上。 具体地址为: lb://openfeign-client/client/**
filters:
- StripPrefix=1 # 请求转发时,会自动过滤请求转发的第一节地址,即client。最终地址为: lb://openfeign-client/**
- AddRequestParameter=id, 0 # 在请求中自动增加一个请求参数,参数名为id,参数值为0。可以用于提供固定参数。
- AddRequestParameter=name, testFilter # 每个AddRequestParameter过滤器,只能提供一个请求参数,提供多请求参数,需要定义多个过滤器。
- AddRequestHeader=my-header, test-header-value # 在请求中自动增加一个请求头参数,参数名为my-header,参数值为test-header-value。
- Authentication=token
- name: Hystrix # 开启Hystrix容错过滤器
args:
name: fallbackcmd # 熔断错误
fallbackUri: forward:/fallback # 出现服务调用问题,访问的本地路径是什么,也就是本地熔断处理逻辑
- id: openfeign-service
uri: lb://openfeign-service
predicates:
- Path=/service/**
filters:
- StripPrefix=1
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
hystrix:
command:
default:
execution:
timeout:
# 如果enabled设置为false,则请求超时交给ribbon控制,为true,则超时作为容错根据
enabled: true
isolation:
thread:
timeoutInMilliseconds: 1000 # 超时时间,默认1000ms
4. 启动类
package
需要更多Java学习资料的小伙伴可以到评论区留言或私信我获取哦