Spring Cloud Gateway:
Spring Cloud Gateway是基于Spring生态系统之上构建的API网关,包括:Spring 5.x,Spring Boot 2.x和Project Reactor。Spring Cloud Gateway旨在提供一种简单而有效的方法来路由到API,并为它们提供跨领域的关注点,例如:安全性,监视/指标,限流等。
什么是服务网关:
API Gateway(APIGW / API 网关),顾名思义,是系统对外的唯一入口。
为什么要使用网关:
微服务的应用可能部署在不同机房,不同地区,不同域名下。此时客户端(浏览器/手机/软件工具)想 要请求对应的服务,都需要知道机器的具体 IP 或者域名 URL,当微服务实例众多时,这是非常难以记忆的,对 于客户端来说也太复杂难以维护。此时就有了网关,客户端相关的请求直接发送到网关,由网关根据请求标识 解析判断出具体的微服务地址,再把请求转发到微服务实例。这其中的记忆功能就全部交由网关来操作了。
核心概念:
路由(Route):路由是网关最基础的部分,路由信息由 ID、目标 URI、一组断言和一组过滤器组成。如果断言 路由为真,则说明请求的 URI 和配置匹配。
断言(Predicate):Java8 中的断言函数。Spring Cloud Gateway 中的断言函数输入类型是 Spring 5.0 框架中 的 ServerWebExchange。Spring Cloud Gateway 中的断言函数允许开发者去定义匹配来自于 Http Request 中的任 何信息,比如请求头和参数等。
过滤器(Filter):一个标准的 Spring Web Filter。Spring Cloud Gateway 中的 Filter 分为两种类型,分别是 Gateway Filter 和 Global Filter。过滤器将会对请求和响应进行处理。
原理:
客户端向 Spring Cloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。
使用网关:
1、添加依赖
<!-- spring cloud gateway 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2、resources/application.yml配置文件
server:
port: 8080
spring:
application:
name: xxx-gateway
cloud:
gateway:
routes:
# 系统模块
- id: xxx-system #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:9201/ #匹配后提供服务的路由地址
predicates:
- Path=/system/**
filters:
- StripPrefix=1
解释:配置了一个 id 为xxx-system 的路由规则,如果浏览器的请求路径,匹配上了 Path=/system/** ,则此处predicates断言为真。就会去访问对应的uri http://localhost:9201/system/**
提示:网关服务,用于路由转发、异常处理、限流、降级、接口、鉴权等等。
路由规则
Spring Cloud Gateway创建Route对象时, 使用RoutePredicateFactory创建Predicate对象,Predicate对象可以赋值给Route。
Spring Cloud Gateway包含许多内置的Route Predicate Factories。
所有这些断言都匹配 HTTP 请求的不同属性。
多个Route Predicate Factories可以通过逻辑与(and)结合起来一起使用。
路由断言工厂包含的主要实现类如图所示,包括Datetime、请求的远端地址、路由权重、请求头、Host 地址、请求方法、请求路径和请求参数等类型的路由断言。
Predicate 来源于 Java 8,是 Java 8 中引入的一个函数,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。可以用于接口请求参数校验、判断新老数据是否有变化需要进行更新操作。
在 Spring Cloud Gateway 中 Spring 利用 Predicate 的特性实现了各种路由匹配规则,有通过 Header、请求参数等不同的条件来进行作为条件匹配到对应的路由。网上有一张图总结了 Spring Cloud 内置的几种 Predicate 的实现。
Datetime
匹配日期时间之后发生的请求
predicates:
- After=2021-02-23T14:20:00.000+08:00[Asia/Shanghai]
After:在这个时间之前生效
Before:在这个时间之前生效
Between在这两个时间之间生效
Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
Cookie
匹配指定名称且其值与正则表达式匹配的cookie
Cookie Route Predicate需要两个参数,一个是Cookie name ,一个是正则表达式。
路由规则会通过获取对应的Cookie name值和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行。
predicates:
- Cookie=loginname, ruoyi
Header
匹配具有指定名称的请求头,\d+值匹配正则表达式
两个参数:一个是属性名称和一个正则表达式,这个属性值和正则表达式匹配则执行。
predicates:
- Header=X-Request-Id, \d+
Host
匹配主机名的列表
predicates:
- Host=**.somehost.org,**.anotherhost.org
Method
匹配请求methods的参数,它是一个或多个参数
predicates:
- Method=GET,POST
Path
匹配请求路径
predicates:
- Path=/system/**
Query
匹配查询参数
predicates:
- Query=username, abc.
RemoteAddr
匹配IP地址和子网掩码
predicates:
- RemoteAddr=192.168.10.1/0
Weight
匹配权重
routes:
- id: xxx-system-a
uri: http://localhost:9201/
predicates:
- Weight=group1, 8
- id: xxx-system-b
uri: http://localhost:9201/
predicates:
- Weight=group1, 2
Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理。
路由配置
在spring cloud gateway中配置uri有三种方式,包括
websocket配置方式
uri: ws://localhost:9090/
http地址配置方式
uri: http://localhost:9090/
注册中心配置方式
uri: lb://xxx-api
实现动态路由需要注意的是uri的协议为lb,表示启用Gateway的负载均衡功能。
当服务提供者有多个时,Gateway会根据注册中心注册的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能
全局过滤器
全局过滤器作用于所有的路由,不需要单独配置,我们可以用它来实现很多统一化处理的业务需求,比如权限认证,IP访问限制等等。目前网关统一鉴权AuthFilter.java就是采用的全局过滤器。
单独定义只需要实现GlobalFilter, Ordered这两个接口就可以了。
@Component
public class AuthFilter implements GlobalFilter, Ordered
{
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
{
// 获取请求参数中的 token
String token = exchange.getRequest().getQueryParams().getFirst("token");
if (null == token)
{
ServerHttpResponse response = exchange.getResponse();
response.getHeaders().add("Content-Type", "application/json; charset=utf-8");
String message = "{\"message\":\"请求token信息不能为空\"}";
DataBuffer buffer = response.bufferFactory().wrap(message.getBytes());
return response.writeWith(Mono.just(buffer));
}
return chain.filter(exchange);
}
/**
* 加载过滤器顺序,数字越小优先级越高
* @return
*/
@Override
public int getOrder()
{
return 0;
}
}
自定义过滤器的方法是实现GlobalFilter接口、实现Ordered接口。这两个接口的全路径为:
org.springframework.cloud