SpringCloud -- Gateway
- Gateway 网关概述
- Gateway 的功能
- Gateway 核心概念
- Gateway 网关搭建
- Gateway 的配置及使用
- predicate 断言
- filter 过滤器
- GlobalFilter 全局过滤器
- Gateway 的几点问题
- 过滤器执行顺序
- 跨域问题
Gateway 网关概述
Gateway 的功能
在微服务当中,有很多的服务需要进行维护,不同服务都维护着不同的 ip 和路径。为了可以对各种杂乱的服务进行统一的分配和管理,研究人员便研究出 Gateway 网关。网关相当于我们的服务群的统一入口,所有外部的请求都必须通过这个“大门”,并在网关的指导下顺利访问到相应的服务。
Spring Cloud GateWay 基于 Spring5.0 + SpringBoot2.0 + WebFlux 等技术开发,性能高于Zuul,其不仅提供统一的路由方式,还基于 Filter 链的方式提供了网关基本的功能,如鉴权、流量控制、熔断、路径重写、日志监控等。
Gateway 核心概念
-
路由 route:路由是网关中的核心,所有的配置都在一个路由中进行,路由的信息包括 ID、目的 URL、一组断言工厂以及一过滤器;
-
断言 predicates:断言定义了 URL 的匹配规则,若断言为真,则当前请求符合该路由规则,规则中的配置则会对该请求生效,断言函数可以由开发者自定义;
-
过滤器 Filter:过滤器可以对请求和响应进行处理,也可以由开发者自定义;
Gateway 网关搭建
在前文所述的项目 SpringCloudAlibabaDemo(【应用】SpringCloud – Nacos)下创建 gateway9005 微服务模块,引入下列依赖
<dependencies>
<!-- SpringCloud alibaba nacos-config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- SpringCloud alibaba nacos discovery-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
使用 nacos 作为配置中心,编写 bootstrap.yml 配置 nacos 相关信息
server:
port: 9005
spring:
application:
name: nacos-config-gateway
cloud:
nacos:
discovery:
server-addr: <nacos-server-ip>:8848 #nacos服务注册中心地址
config:
server-addr: <nacos-server-ip>:8848 #nacos作为配置中心地址
file-extension: yml #指定yml格式的配置
group: TEST_GROUP # 分组,若不指定则默认为DEFAULT_GROUP
namespace: 3c0dd568-f5a1-437a-a8c7-1a17125e8e65 # 命名空间,若不指定则默认为public
创建项目的配置文件 application.yml
spring:
profiles:
active: dev
在 nacos 下的相应的命名空间的相应分组下按照命名规则创建 gateway 的配置文件,下图为本文配置所对应的配置文件
最后创建 gateway 微服务启动类,至此一个简单的 gateway 服务搭建完成,其重点在于路由配置以及使用
@SpringBootApplication
public class Gateway9005 {
public static void main(String[] args) {
SpringApplication.run(Gateway9005.class);
}
}
Gateway 的配置及使用
先来看一下 nacos 中一个简单的路由配置
server:
port: 9005
spring:
application:
name: nacos-config-gateway
cloud:
nacos:
server-addr: <nacos-server-ip>:8848
gateway:
routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
- id: test_route # 当前路由的标识, 要求唯一
uri: lb://nacos-order-consumer # 请求要转发到的地址
order: 1 # 路由的优先级,数字越小级别越高
predicates: # 断言(就是路由转发要满足的条件)
- Path=/gateway/**
# - Query=gateway
# - After=2023-01-20T17:42:47.789-07:00[Asia/Shanghai]
# - Before=
# - Between=
# - Method=POST
# - Header=Warning,\d+
# - Host=localhost:9005
filters: # 过滤器
- StripPrefix=1 #转发之前去掉1层路径
- AddRequestHeader=gateway, hello!
- AddRequestParameter=queryParam, hello222!
- AddResponseHeader=zzz, cool!
# - PrefixPath=/gateway
default-filters: #默认过滤器,会对所有的路由请求都生效
- AddResponseHeader=zzzz, coolcool!
在spring-cloud-gateway
中可以配置不同的路由组,对不同的请求进行配置,在每一个路由中,包含由 id、uri、predicates、filters 等设置:
-
id
:当前路由的唯一标识,不可重复; -
uri
:匹配该路由的请求的转发地址(此处配合 nacos 使用,lb 代表负载均衡,后面的名字为微服务在 nacos 注册中心中注册的服务名); -
predicates
:断言,若断言为真,则对应请求将遵循该路由组配置; -
filters
:过滤器,处理请求以及响应;
predicate 断言
常用的断言配置如下:附[官方文档]((https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories)
属性 | 说明 | 概述 |
---|---|---|
Path | 基于请求路径进行判断 | 接收一个或者多个请求路径,判断请求路径是否相符合 |
Query | 基于请求参数进行判断 | 接收两个参数,其一为请求的 param,其二为正则表达式,判断接收到的参数是否与正则表达式相匹配 |
After | 基于请求时间进行判断 | 接收一个参数,判断请求的时间是否在配置的时间之后 |
Before | 基于请求时间进行判断 | 接收一个参数,判断请求的时间是否在配置的时间之前 |
Between | 基于请求时间进行判断 | 接收一个参数,判断请求的时间是否在配置的时间之间 |
Method | 基于请求方式进行判断 | 接收一个参数,判断请求的方式是否与配置相符合 |
Header | 基于请求头进行判断 | 接收两个参数,其一为请求头属性,其二为正则表达式,判断接收到的请求头是否与正则表达式相匹配 |
Host | 基于请求主机进行判断 | 接收一个参数主机名,判断请求的 Host 是否与配置相符 |
… | … | … |
附:正则表达式总结
filter 过滤器
常用的过滤器配置如下:附[官方文档](Spring Cloud Gateway)
过滤器 | 说明 | 参数 |
---|---|---|
AddRequestHeader | 为原始请求添加 Header | Header 的名称以及值 |
AddRequestParameter | 为原始请求添加请求参数 | 参数名称以及值 |
AddResponseHeader | 为原始响应添加 Header | Header 的名称以及值 |
PrefixPath | 为原始请求路径添加前缀 | 添加的前缀路径 |
StripPrefix | 为原始请求去除 x 层路径 | 数值 x 代表去除层数 |
… | … | … |
GlobalFilter 全局过滤器
全局过滤器与上述过滤器最大的区别在于其通过手写代码定义过滤逻辑,而不是在配置文件中进行配置,其过滤逻辑更加多样化。
示例:对请求参数中的Authorization
字段进行判断,依据规则判断是否放行请求
@Order(-1) // 多个过滤器存在时该值表现为优先级,该值越小优先级越高
@Component
public class AuthorizationFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> queryParams = request.getQueryParams();
// 2. 获取对应属性的值
String auth = queryParams.getFirst("Authorization");
// 3. 执行判断逻辑
// 3.1 通过验证,放行
if ("leo".equals(auth)) {
return chain.filter(exchange);
}
// 3.2 验证失败,进行拦截
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
}
重新启动代码进行测试,当请求不携带任何参数时,请求被拦截,访问失败
当请求携带响应参数并符合规则时放行
Gateway 的几点问题
过滤器执行顺序
在网关中存在着路由过滤器、全局过滤器以及默认过滤器三种类型的过滤器,三种过滤器会按照设置的优先级合并排列在一个过滤器链中,然后依次执行。
每一个过滤器都必须设定 order 值:
-
全局过滤器的 order 通过注解
@order
设定; -
路由过滤器和默认过滤器的 order 由 Spring 指定,按照声明顺序从 1 递增;
当过滤器的 order 值一样时,会按照默认过滤器 > 路由过滤器 > 全局过滤器
的顺序执行。
跨域问题
跨域:当一个服务请求另一个服务时,两者的协议、域名、端口三者之间任意一个不同都即为跨域
使用 Gateway 配置解决跨域问题
gateway:
globalcors:
cors-configurations:
'[/**]':
allowCredentials: true
allowedOrigins: "*"
allowedMethods: "*"
allowedHeaders: "*" #允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期