目录
SpringCloud Gateway的Predicate断言:
SpringCloud Gateway的Filter过滤器:
什么是API网关:
API 网关是一个搭建在客户端和微服务之间的服务,我们可以在 API 网关中处理一些非业务功能的逻辑,例如权限验证、监控、缓存、请求路由等;API 网关就像整个微服务系统的门面一样,是系统对外的唯一入口。客户端会先将请求发送到 API 网关,然后由 API 网关根据请求的标识信息将请求转发到微服务实例。
在微服务架构中,一个系统往往由多个微服务组成,而这些服务可能部署在不同机房、不同地区、不同域名下。这种情况下,客户端(例如浏览器、手机、软件工具等)想要直接请求这些服务,就需要知道它们具体的地址信息,例如 IP 地址、端口号等。像这样服务数量众多、复杂度较高、规模比较大的系统来说,考虑以下场景:
- 当服务数量众多时,客户端需要维护大量的服务地址,对于客户端来说,是非常繁琐复杂的。
- 在某些场景下可能会存在跨域请求的问题。
- 身份认证的难度大,每个微服务需要独立认证。
使用 API 网关的好处:
- 客户端通过 API 网关与微服务交互时,客户端只需要知道 API 网关地址即可,而不需要维护大量的服务地址,简化了客户端的开发。
- 客户端直接与 API 网关通信,能够减少客户端与各个服务的交互次数。
- 客户端与后端的服务耦合度降低。
- 节省流量,提高性能,提升用户体验。
- API 网关还提供了安全、流控、过滤、缓存、计费以及监控等 API 管理功能。
流量网关:
流量网关,顾名思义就是控制流量进入集群的网关,有很多工作需要在这一步做,对于一个服务集群,势必有很多非法的请求或者无效的请求,这时候要将请求拒之门外,降低集群的流量压力。
定义全局性的、跟具体的后端业务应用和服务完全无关的策略网关就是上图所示的架构模型——流量网关。流量网关通常只专注于全局的Api管理策略,比如全局流量监控、日志记录、全局限流、黑白名单控制、接入请求到业务系统的负载均衡等,有点类似防火墙。Kong 就是典型的流量网关。
业务网关:
业务网关一般部署在流量网关之后、业务系统之前,比流量网关更靠近业务系统。通常API网指的是业务网关;
当一个单体应用被拆分成许许多多的微服务应用后,也带来了一些问题。一些与业务非强相关的功能,比如权限控制、日志输出、数据加密、熔断限流等,每个微服务应用都需要,因此存在着大量重复的代码实现。而且由于系统的迭代、人员的更替,各个微服务中这些功能的实现细节出现了较大的差异,导致维护成本变高。另一方面,原先单体应用下非常容易做的接口管理,在服务拆分后没有了一个集中管理的地方,无法统计已存在哪些接口、接口定义是什么、运行状态如何。
网关就是为了解决上述问题。作为微服务体系中的核心基础设施,一般需要具备接口管理、协议适配、熔断限流、安全防护等功能,各种开源的网关产品(比如 zuul)都提供了优秀高可扩展性的架构、可以很方便的实现我们需要的一些功能、比如鉴权、日志监控、熔断限流等。
与流量网关相对应的就是业务网关,业务网关更靠近我们的业务,也就是与服务器应用层打交道,那么有很多应用层需要考虑的事情就可以依托业务网关,例如在线程模型、协议适配、熔断限流,服务编排等。下面看看业务网关体系结构:
目前业务网关比较成熟的 API 网关框架产品有三个 分别是:Zuul1、Zuul2 和 SpringCloud Gateway;
常见的 5 种 API 网关实现方案:
OpenResty
Kong
Zuul、Zuul2
Spring Cloud Gateway
1.OpenResty
OpenResty是一个流量网关,OpenResty基于 Nginx与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
通过揉和众多设计良好的 Nginx 模块,OpenResty 有效地把 Nginx 服务器转变为一个强大的 Web 应用服务器,基于它开发人员可以使用 Lua 编程语言对 Nginx 核心以及现有的各种 Nginx C 模块进行脚本编程,构建出可以处理一万以上并发请求的极端高性能的 Web 应用
OpenResty 最早是顺应 OpenAPI 的潮流做的,所以 Open 取自“开放”之意,而Resty便是 REST 风格的意思。虽然后来也可以基于 ngx_openresty 实现任何形式的 web service 或者传统的 web 应用。
也就是说 Nginx 不再是一个简单的静态网页服务器,也不再是一个简单的反向代理了。第二代的 openresty 致力于通过一系列 nginx 模块,把nginx扩展为全功能的 web 应用服务器。
ngx_openresty 是用户驱动的项目,后来也有不少国内用户的参与,从 openresty.org 的点击量分布上看,国内和国外的点击量基本持平。
ngx_openresty 目前有两大应用目标:
通用目的的 web 应用服务器。在这个目标下,现有的 web 应用技术都可以算是和 OpenResty 或多或少有些类似,比如 Nodejs, PHP 等等。ngx_openresty 的性能(包括内存使用和 CPU 效率)算是最大的卖点之一。
Nginx 的脚本扩展编程,用于构建灵活的 Web 应用网关和 Web 应用防火墙。有些类似的是 NetScaler。其优势在于 Lua 编程带来的巨大灵活性。
2. Kong
Kong基于OpenResty开发,也是流量层网关, 是一个云原生、快速、可扩展、分布式的Api 网关。继承了OpenResty的高性能、易扩展性等特点。Kong通过简单的增加机器节点,可以很容易的水平扩展。同时功能插件化,可通过插件来扩展其能力。而且在任何基础架构上都可以运行。具有以下特性:
提供了多样化的认证层来保护Api。
可对出入流量进行管制。
提供了可视化的流量检查、监视分析Api。
能够及时的转换请求和相应。
提供log解决方案
可通过api调用Serverless 函数。
当我们决定对应用进行微服务改造时,应用客户端如何与微服务交互的问题也随之而来,毕竟服务数量的增加会直接导致部署授权、负载均衡、通信管理、分析和改变的难度增加。
面对以上问题,API GATEWAY是一个不错的解决方案,其所提供的访问限制、安全、流量控制、分析监控、日志、请求转发、合成和协议转换功能,可以解放开发者去把精力集中在具体逻辑的代码,而不是把时间花费在考虑如何解决应用和其他微服务链接的问题上。
Kong的优点以及性能:
专注于全局的Api管理策略,全局流量监控、日志记录、全局限流、黑白名单控制、接入请求到业务系统的负载均衡等。在众多 API GATEWAY 框架中,Mashape 开源的高性能高可用API网关和API服务管理层——KONG(基于 NGINX+Lua)特点尤为突出,它可以通过插件扩展已有功能,这些插件(使用 lua 编写)在API请求响应循环的生命周期中被执行。于此同时,KONG本身提供包括 HTTP 基本认证、密钥认证、CORS、TCP、UDP、文件日志、API请求限流、请求转发及 NGINX 监控等基本功能。
Kong架构:
首先最底层是基于Nginx, Nginx是高性能的基础层, 一个良好的负载均衡、反向代理器,然后在此基础上增加Lua脚本库,形成了OpenResty,拦截请求, 响应生命周期,可以通过Lua编写脚本,所以插件比较丰富;
3. Zuul1.0
Zuul是所有从设备和web站点到Netflix流媒体应用程序后端请求的前门。作为一个边缘服务应用程序,Zuul被构建来支持动态路由、监视、弹性和安全性。它还可以根据需要将请求路由到多个Amazon自动伸缩组。
Zuul使用了一系列不同类型的过滤器,使我们能够快速灵活地将功能应用到服务中。
过滤器
过滤器是Zuul的核心功能。它们负责应用程序的业务逻辑,可以执行各种任务。
Type :通常定义过滤器应用在哪个阶段
Async :定义过滤器是同步还是异步
Execution Order :执行顺序
Criteria :过滤器执行的条件
Action :如果条件满足,过滤器执行的动作
Zuul提供了一个动态读取、编译和运行这些过滤器的框架。过滤器之间不直接通信,而是通过每个请求特有的RequestContext共享状态。
下面是Zuul的一些过滤器:
Incoming
Incoming过滤器在请求被代理到Origin之前执行。这通常是执行大部分业务逻辑的地方。例如:认证、动态路由、速率限制、DDoS保护、指标。
Endpoint
Endpoint过滤器负责基于incoming过滤器的执行来处理请求。Zuul有一个内置的过滤器(ProxyEndpoint),用于将请求代理到后端服务器,因此这些过滤器的典型用途是用于静态端点。例如:健康检查响应,静态错误响应,404响应。
Outgoing
Outgoing过滤器在从后端接收到响应以后执行处理操作。通常情况下,它们更多地用于形成响应和添加指标,而不是用于任何繁重的工作。例如:存储统计信息、添加/剥离标准标题、向实时流发送事件、gziping响应。
过滤器类型
下面是与一个请求典型的生命周期对应的标准的过滤器类型:
PRE :路由到Origin之前执行
ROUTING :路由到Origin期间执行
POST :请求被路由到Origin之后执行
ERROR :发生错误的时候执行
这些过滤器帮助我们执行以下功能:
身份验证和安全性 :识别每个资源的身份验证需求,并拒绝不满足它们的请求
监控 :在边缘跟踪有意义的数据和统计数据,以便给我们一个准确的生产视图
动态路由 :动态路由请求到不同的后端集群
压力测试 :逐渐增加集群的流量,以评估性能
限流 :为每种请求类型分配容量,并丢弃超过限制的请求
静态响应处理 :直接在边缘构建一些响应,而不是将它们转发到内部集群
Zuul 1.0 请求生命周期
Netflix宣布了通用API网关Zuul的架构转型。Zuul原本采用同步阻塞架构,转型后叫作Zuul2,采用异步非阻塞架构。Zuul2和Zuul1在架构方面的主要区别在于,Zuul2运行在异步非阻塞的框架上,比如Netty。Zuul1依赖多线程来支持吞吐量的增长,而Zuul 2使用的Netty框架依赖事件循环和回调函数。
4. Zuul2.0
Zuul 2.0 架构图
上图是Zuul2的架构,和Zuul1没有本质区别,两点变化:
前端用Netty Server代替Servlet,目的是支持前端异步。后端用Netty Client代替Http Client,目的是支持后端异步。
过滤器换了一下名字,用Inbound Filters代替Pre-routing Filters,用Endpoint Filter代替Routing Filter,用Outbound Filters代替Post-routing Filters。
Inbound Filters :路由到 Origin 之前执行,可以用于身份验证、路由和装饰请求
Endpoint Filters :可用于返回静态响应,否则内置的ProxyEndpoint过滤器将请求路由到Origin
Outbound Filters :从Origin那里获取响应后执行,可以用于度量、装饰用户的响应或添加自定义header
有两种类型的过滤器:sync 和 async。因为Zuul是运行在一个事件循环之上的,因此从来不要在过滤中阻塞。如果你非要阻塞,可以在一个异步过滤器中这样做,并且在一个单独的线程池上运行,否则可以使用同步过滤器,Zuul2开始采用了异步模型;
优势 是异步非阻塞模式启动的线程很少,基本上一个CPU core上只需启一个事件环处理线程,它使用的线程资源就很少,上下文切换(Context Switch)开销也少。非阻塞模式可以接受的连接数大大增加,可以简单理解为请求来了只需要进队列,这个队列的容量可以设得很大,只要不超时,队列中的请求都会被依次处理。
不足 ,异步模式让编程模型变得复杂。一方面Zuul2本身的代码要比Zuul1复杂很多,Zuul1的代码比较容易看懂,Zuul2的代码看起来就比较费劲。另一方面异步模型没有一个明确清晰的请求->处理->响应执行流程(call flow),它的流程是通过事件触发的,请求处理的流程随时可能被切换断开,内部实现要通过一些关联id机制才能把整个执行流再串联起来,这就给开发调试运维引入了很多复杂性,比如你在IDE里头调试异步请求流就非常困难。另外ThreadLocal机制在这种异步模式下就不能简单工作,因为只有一个事件环线程,不是每个请求一个线程,也就没有线程局部的概念,所以对于CAT这种依赖于ThreadLocal才能工作的监控工具,调用链埋点就不好搞(实际可以工作但需要进行特殊处理)。
总体上,异步非阻塞模式比较适用于IO密集型(IO bound)场景,这种场景下系统大部分时间在处理IO,CPU计算比较轻,少量事件环线程就能处理。
Zuul 与 Zuul 2 性能对比
Netflix给出了一个比较模糊的数据,大致Zuul2的性能比Zuul1好20%左右 ,这里的性能主要指每节点每秒处理的请求数。为什么说模糊呢?因为这个数据受实际测试环境,流量场景模式等众多因素影响,你很难复现这个测试数据。即便这个20%的性能提升是确实的,其实这个性能提升也并不大,和异步引入的复杂性相比,这20%的提升是否值得是个问题。
5. Spring Cloud Gateway
本文章下面会重点介绍Spring Cloud Gateway,我们先来看一下几种网关的对比:
Spring Cloud Gateway 网关:
SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty;
Spring WebFlux 是 Spring Framework 5.0中引入的新的响应式web框架。与Spring MVC不同,它不需要Servlet API,是完全异步且非阻塞的,并且通过Reactor项目实现了Reactive Streams规范。Spring WebFlux 用于创建基于事件循环执行模型的完全异步且非阻塞的应用程序。(PS:所谓异步非阻塞是针对服务端而言的,是说服务端可以充分利用CPU资源去做更多事情,这与客户端无关,客户端该怎么请求还是怎么请求。)
Netty是一个基于JAVA NIO 类库的异步通信框架,它的架构特点是:异步非阻塞、基于事件驱动、高性能、高可靠性和高可定制性;
Spring Cloud GateWay 路由转发功能:
Spring Cloud GateWay 最主要的功能就是路由转发,而在定义转发规则时主要涉及了以下三个核心概念:路由、断言、过滤器(注意:其中 路由 和 断言 必须同时声明);
server:
port: 7000
spring:
application:
name: gateway-server # 应用名称
cloud:
gateway:
# 路由规则
routes:
- id: shop-goods # 路由 ID,唯一
uri: http://localhost:9101/ # 目标URI,路由到微服务的地址
predicates: # 断言(判断条件)
- Path=/goods/** # 匹配对应URL的请求,将匹配到的请求追加在目标URI之后
filters:
- AddRequestParameter=X-Request-Id,1024 #过滤器工厂会在匹配的请求头加上一对请求头,名称为 X-Request-Id 值为 1024
- PrefixPath=/dept #在请求路径前面加上 /dept
Route (路由):
网关配置的基本组成模块,和Zuul的路由配置模块类似。一个Route模块 由一个 ID,一个目标 URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配,目标URI会被访问。
Predicate (断言):
这是一个 Java 8 的 Predicate,可以使用它来匹配来自 HTTP 请求的任何内容,例如请求方式、请求路径、请求头、参数等。断言的 输入类型是一个 ServerWebExchange;
Filter (过滤器):
可以使用它拦截和修改请求,并且对上游的响应,进行二次处理。过滤器为org.springframework.cloud.gateway.filter.GatewayFilter类的实例。
SpringCloud Gateway 最主要的特征:
(1)基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0;
(2)集成 Hystrix 断路器;
(3)集成 Spring Cloud DiscoveryClient服务注册;
(4)Predicates 和 Filters 作用于特定路由,易于编写的 Predicates 和 Filters;
(5)具备一些网关的高级功能:动态路由、限流、路径重写;
SpringCloud Gateway 工作流程:
- 客户端将请求发送到 Spring Cloud Gateway 上。
- Spring Cloud Gateway 通过 Gateway Handler Mapping 找到与请求相匹配的路由,将其发送给 Gateway Web Handler。
- Gateway Web Handler 通过指定的过滤器链(Filter Chain),将请求转发到实际的服务节点中,执行业务逻辑返回响应结果。
- 过滤器之间用虚线分开是因为过滤器可能会在转发请求之前(pre)或之后(post)执行业务逻辑。
- 过滤器(Filter)可以在请求被转发到服务端前,对请求进行拦截和修改,例如参数校验、权限校验、流量监控、日志输出以及协议转换等。
- 过滤器可以在响应返回客户端之前,对响应进行拦截和再处理,例如修改响应内容或响应头、日志输出、流量监控等。
- 响应原路返回给客户端。
总结:Predicate (断言)就是路由的匹配条件,而 Filter (过滤器)就是对请求和响应进行精细化控制的工具。通过这两个元素,再加上目标 URI,就可以实现一个具体的路由了;
SpringCloud Gateway的Predicate断言:
Predicate 是路由转发的判断条件,请求只有满足了 Predicate 的条件,才会被转发到指定的服务上进行处理;使用时需要注意以下三点:
- Route 路由与 Predicate 断言的对应关系为“一对多”,一个路由可以包含多个不同断言。
- 一个请求想要转发到指定的路由上,就必须同时匹配路由上的所有断言。
- 当一个请求同时满足多个路由的断言条件时,请求只会被首个成功匹配的路由转发。
常见的 Predicate 断言:
SpringCloud Gateway的URL和动态路由:
下面的配置文件中Route下的 uri 填写的路径是目标地址的URI,路由到微服务实例的真实地址,我们还可以通过服务注册中心实现动态路由;
server:
port: 7000
spring:
application:
name: gateway-server # 应用名称
cloud:
gateway:
# 路由规则
routes:
- id: shop-goods # 路由 ID,唯一
uri: http://localhost:9101/ # 目标URI,路由到微服务的地址
predicates: # 断言(判断条件)
- Path=/goods/** # 匹配对应URL的请求,将匹配到的请求追加在目标URI之后
filters:
- AddRequestParameter=X-Request-Id,1024 #过滤器工厂会在匹配的请求头加上一对请求头,名称为 X-Request-Id 值为 1024
- PrefixPath=/dept #在请求路径前面加上 /dept
如果我们想实现动态路由,我们可以在配置文件中将 Route 的 uri 地址修改为以下形式:
uri: lb://service-name # 目标URI,路由到微服务的地址
Spring Cloud Gateway 会根据服务注册中心(例如nacos)中维护的服务列表,以服务名(spring.application.name)作为路径创建动态路由进行转发,从而实现动态路由功能。以nacos为例我们看一下Gateway的配置文件如何介入到注册服务中心并实现 Spring Cloud Gateway 动态路由;
server:
port: 7000
spring:
application:
name: gateway-server # 应用名称
cloud:
gateway:
# 路由规则
routes:
- id: shop-goods # 路由 ID,唯一
uri: lb://shop-goods # 根据服务名称从注册中心获取服务请求地址
predicates: # 断言(判断条件)
- Path=/goods/** # 匹配对应 URL 的请求,将匹配到的请求追加在目标 URI 之后
#- Query=token # 匹配请求参数中包含 token 的请求
#- Query=token, abc. # 匹配请求参数中包含 token ,并且参数的值 满足正则表达式 abc. 的请求
#- Method=POST # 匹配任意 POST 请求
#- After=2021-04-25T10:00:00+08:00[Asia/Shanghai] # 匹配 2021-4-25 10:00:00之后
#- Before=2021-04-25T10:00:00+08:00[Asia/Shanghai] # 匹配这个时间之前
#- Between=2021-04-25T10:00:00+08:00[Asia/Shanghai],2021-04-25T12:00:00+08:00[Asia/Shanghai] # 匹配两个时间之间
#- RemoteAddr=192.168.100.233/24 # 匹配远程地址是RemoteAddr的请求,24 表示子网掩码
#- Header=token, \d+ # 请求头携带token \d+ 值得正则表达式
nacos:
# 注册中心配置
discovery:
server-addr: localhost:8848 # nacos 注册中心地址
namespace: 0e883794-4414-4d41-a177-6d335d304e42 # 开发环境 指定 具体的命名空间id
#group: DEFAULT_GROUP # 分组 默认分组可以省略
# 配置中心配置
config:
#enabled: false #关闭配置
server-addr: localhost:8848 # Nacos 配置中心地址
namespace: 0e883794-4414-4d41-a177-6d335d304e42 # 开发环境 指定 具体的命名空间id
group: TEST_GROUP # 分组
name: test-config-dev #dataid 内容
动态路由的转发过程:
1.通过配置文件或者代码实现的方式将Gateway网关和微服务实例注册到nacos服务列表中
2.通过Gateway网关路由下定义的断言规则匹配到目标URL,如果是lb://开头的证明是通过注册中心获取真实的请求地址
3.根据uri: lb://后边的服务名去注册服务中心维护的服务列表中找到匹配的真实IP和端口
4.获取到的真实IP和端口号再拼接上断言中填写的路径和规则
5.最后根据过滤器的配置项再拼接一下请求参数
6.完成一个动态路由的请求转发
SpringCloud Gateway的Filter过滤器:
通常情况下,出于安全方面的考虑,服务端提供的服务往往都会有一定的校验逻辑,例如用户登陆状态校验、签名校验等。在微服务架构中,系统由多个微服务组成,所有这些服务都需要这些校验逻辑,此时我们就可以将这些校验逻辑写到 Spring Cloud Gateway 的 Filter 过滤器中。
Filter 的分类:
按照作用范围划分,Spring Cloud gateway 的 Filter 可以分为 2 类:
- GatewayFilter:应用在单个路由或者一组路由上的过滤器。
- GlobalFilter:应用在所有的路由上的过滤器。
1.GatewayFilter 网关过滤器:
GatewayFilter 是 Spring Cloud Gateway 网关中提供的一种应用在单个或一组路由上的过滤器。它可以对单个路由或者一组路由上传入的请求和传出响应进行拦截,并实现一些与业务无关的功能,比如登陆状态校验、签名校验、权限校验、日志输出、流量监控等。
GatewayFilter 在配置文件(例如 application.yml)中的写法:
spring:
cloud:
gateway:
routes:
- id: xxxx
uri: xxxx
predicates:
- Path=xxxx
filters:
- AddRequestParameter=X-Request-Id,1024 #过滤器工厂会在匹配的请求头加上一对请求头,名称为 X-Request-Id 值为 1024
- PrefixPath=/dept #在请求路径前面加上 /dept
……
Spring Cloud Gateway 内置了多达 31 种 GatewayFilter,常用的网关过滤器:
2.GlobalFilter 全局过滤器:
GlobalFilter 是一种作用于所有的路由上的全局过滤器,通过它,我们可以实现一些统一化的业务功能,例如权限认证、IP 访问限制等。当某个请求被路由匹配时,那么所有的 GlobalFilter 会和该路由自身配置的 GatewayFilter 组合成一个过滤器链。
Spring Cloud Gateway 为我们提供了多种默认的 GlobalFilter,例如与转发、路由、负载均衡等相关的全局过滤器。但在实际的项目开发中,通常我们都会自定义一些自己的 GlobalFilter 全局过滤器以满足我们自身的业务需求,而很少直接使用 Spring Cloud Config 提供这些默认的 GlobalFilter。
如何自定义 GlobalFilter 全局过滤器:
示例新建一个名为 MyGlobalFilter 全局过滤器配置类,代码如下:
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Date;
/**
* 自定义全局网关过滤器(GlobalFilter)
*/
@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("进入自定义的全局过滤器 MyGlobalFilter" + new Date());
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if (uname == null) {
log.info("参数 uname 不能为 null!");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
//过滤器的顺序,0 表示第一个 越小优先级越高
return 0;
}
}
SpringCloud Gateway的跨域配置:
在前端领域中,跨域是指浏览器允许向服务器发送跨域请求,从而克服Ajax只能同源使用的限制。 同源策略(Same Orgin Policy)是一种约定,它是浏览器核心也最基本的安全功能,它会阻止一个域的js脚 本和另外一个域的内容进行交互,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源 (即在同一个域)就是两个页面具有相同的协议(protocol)、主机(host)和端口号(port)。
1.通过yml配置的方式:
spring:
cloud:
gateway:
globalcors:
cors‐configurations:
'[/**]':
allowedOrigins: "*"
allowedMethods:
‐ GET
‐ POST
‐ DELETE
‐ PUT
‐ OPTION
2.通过java配置的方式:
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new
PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
SpringCloud Gateway的限流:
1.基于redis+lua脚本限流
1)添加依赖
1 <dependency>
2 <groupId>org.springframework.boot</groupId>
3 <artifactId>spring‐boot‐starter‐data‐redis‐reactive</artifactId>
4 </dependency>
2)修改 application.yml ,添加redis配置和RequestRateLimiter过滤器工厂配
1 spring:
2 application:
3 name: mall‐gateway
4
5 redis:
6 host: localhost
7 port: 6379
8 database: 0
9 timeout: 5000
10 lettuce:
11 pool:
12 max‐active: 200
13 max‐wait: 10000
14 max‐idle: 100
15 min‐idle: 10
16 #配置nacos注册中心地址
17 cloud:
18 nacos:
19 discovery:
20 server‐addr: 127.0.0.1:8848
21
22 gateway:
23 #设置路由:路由id、路由到微服务的uri、断言
24 routes:
25 ‐ id: order_route #路由ID,全局唯一,建议配置服务名
26 # 测试 http://localhost:8888/order/findOrderByUserId/1
27 uri: lb://mall‐order #lb 整合负载均衡器ribbon,loadbalancer
28 predicates:
29 ‐ Path=/order/** # 断言,路径相匹配的进行路由
30 #配置过滤器工厂
31 filters:
32 ‐ name: RequestRateLimiter #限流过滤器
33 args:
34 redis‐rate‐limiter.replenishRate: 1 #令牌桶每秒填充速率
35 redis‐rate‐limiter.burstCapacity: 2 #令牌桶的总容量
36 key‐resolver: "#{@keyResolver}" #使用SpEL表达式,从Spring容器中获取Bean对象
3) 配置keyResolver,可以指定限流策略,比如url限流,参数限流,ip限流等等
1 @Bean
2 KeyResolver keyResolver() {
3 //url限流
4 return exchange ‐> Mono.just(exchange.getRequest().getURI().getPath());
5 //参数限流
6 //return exchange ‐> Mono.just(exchange.getRequest().getQueryParams().getFirst("u
ser"));
7 }
2.sentinel限流
从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的 限流: route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeId 自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组;
当通过 GatewayRuleManager 加载网关流控规则(GatewayFlowRule)时,无论是否针对请 求属性进行限流,Sentinel 底层都会将网关流控规则转化为热点参数规则(ParamFlowRule),存 储在 GatewayRuleManager 中,与正常的热点参数规则相隔离。转换时 Sentinel 会根据请求属性 配置,为网关流控规则设置参数索引(idx),并同步到生成的热点参数规则中。 外部请求进入 API Gateway 时会经过 Sentinel 实现的 filter,其中会依次进行 路由/API 分组匹配、 请求属性解析和参数组装。Sentinel 会根据配置的网关流控规则来解析请求属性,并依照参数索引顺 序组装参数数组,最终传入 SphU.entry(res, args) 中。Sentinel API Gateway Adapter Common 模块向 Slot Chain 中添加了一个 GatewayFlowSlot,专门用来做网关规则的检查。 GatewayFlowSlot 会从 GatewayRuleManager 中提取生成的热点参数规则,根据传入的参数依次 进行规则检查。若某条规则不针对请求属性,则会在参数最后一个位置置入预设的常量,达到普通流 控的效果
1)引入依赖
1 <!‐‐ gateway接入sentinel ‐‐>
2 <dependency>
3 <groupId>com.alibaba.cloud</groupId>
4 <artifactId>spring‐cloud‐alibaba‐sentinel‐gateway</artifactId>
5 </dependency>
6
7 <dependency>
8 <groupId>com.alibaba.cloud</groupId>
9 <artifactId>spring‐cloud‐starter‐alibaba‐sentinel</artifactId>
10 </dependency>
11 <‐‐sentinel规则持久化到nacos‐‐>
12 <dependency>
13 <groupId>com.alibaba.csp</groupId>
14 <artifactId>sentinel‐datasource‐nacos</artifactId>
15 </dependency>
2)添加yml配置,接入sentinel dashboard,通过sentinel控制台配置网关流控规则
1 server:
2 port: 8888
3 spring:
4 application:
5 name: mall‐gateway‐sentinel‐demo
6 main:
7 allow‐bean‐definition‐overriding: true
8 #配置nacos注册中心地址
9 cloud:
10 nacos:
11 discovery:
12 server‐addr: 127.0.0.1:8848
13
14 sentinel:
15 transport:
16 # 添加sentinel的控制台地址
17 dashboard: 127.0.0.1:8080
18 datasource:
19 gateway‐flow‐rules:
20 nacos:
21 server‐addr: 127.0.0.1:8848
22 dataId: ${spring.application.name}‐gateway‐flow‐rules
23 groupId: SENTINEL_GROUP
24 data‐type: json
25 rule‐type: gw‐flow
26 gateway‐api‐rules:
27 nacos:
28 server‐addr: 127.0.0.1:8848
29 dataId: ${spring.application.name}‐gateway‐api‐rules
30 groupId: SENTINEL_GROUP
31 data‐type: json
32 rule‐type: gw‐api‐group
33 degrade‐rules:
34 nacos:
35 server‐addr: 127.0.0.1:8848
36 dataId: ${spring.application.name}‐degrade‐rules
37 groupId: SENTINEL_GROUP
38 data‐type: json
39 rule‐type: degrade
40 system‐rules:
41 nacos:
42 server‐addr: 127.0.0.1:8848
43 dataId: ${spring.application.name}‐system‐rules
44 groupId: SENTINEL_GROUP
45 data‐type: json
46 rule‐type: system
47
48 gateway:
49 #设置路由:路由id、路由到微服务的uri、断言
50 routes:
51 ‐ id: order_route #路由ID,全局唯一,建议配合服务名
52 uri: lb://mall‐order #lb 整合负载均衡器ribbon,loadbalancer
53 predicates:
54 ‐ Path=/order/**
55
56 ‐ id: user_route
57 uri: lb://mall‐user #lb 整合负载均衡器ribbon,loadbalancer
58 predicates:
59 ‐ Path=/user/**