Gateway 网关
# Gateway 网关
# 1. 什么是 SpringCloud Gateway
网关作为流量的入口,常见功能包括路由转发、权限校验、限流等。SpringCloud Gateway 是 Spring Cloud 官方推出的第二代网关框架,旨在取代 Netflix Zuul。相较于 Zuul,SpringCloud Gateway 提供了更优越的性能和更强大的功能。
SpringCloud Gateway 的特点:
- 基于 WebFlux、Netty 和 Reactor,实现了响应式的 API 网关。
- 提供了动态路由、路径重写、服务发现、流控降级等功能。
- 使用 Predicate(断言)和 Filter(过滤器)进行灵活的路由配置和处理。
# 其他网关组件对比
在 SpringCloud 微服务体系中,Zuul 是传统网关的代表,但在 2.x 版本中,Zuul 升级缓慢,SpringCloud 自主研发了 SpringCloud Gateway 来替代 Zuul。
需要注意的是,很多文章提到 Zuul 是阻塞的,而 Gateway 是非阻塞的,这并不完全准确。Zuul 1.x 版本是阻塞的,但在 2.x 版本中,Zuul 也基于 Netty,具备非阻塞能力。两者在性能上的差异并没有明显的区别。
# SpringCloud Gateway 功能特征
- 基于 Spring Framework 5、Project Reactor 和 Spring Boot 2.0 构建。
- 支持动态路由:匹配任意请求属性。
- 支持路径重写。
- 集成服务发现功能(如 Nacos、Eureka)。
- 支持流控降级功能(如 Sentinel、Hystrix)。
- 提供丰富的 Predicate 和 Filter 功能,实现复杂的请求处理逻辑。
# 2. 为什么需要 SpringCloud Gateway
在微服务架构中,系统被拆分为多个微服务,客户端如何调用这些服务呢?如果没有网关,客户端必须记录每个微服务的地址并分别调用。
# 问题分析
这种架构存在以下问题:
- 每个业务都需要实现
鉴权
、限流
、权限校验
、跨域
等逻辑,如果各自为战,重复开发工作量大且不易维护。 - 随着业务复杂度增加,多个微服务协同工作时,客户端需要维护多个域名,难以管理。同时,连接数瓶颈问题会显现,尤其是在移动端下效率低下。
- 如果微服务进行重构,例如将一个服务拆分为多个服务,客户端也需要进行配套改造,增加了系统维护的复杂度。
# 网关的作用
上述问题可以通过网关来解决。网关提供了以下核心功能:
- 权限控制:校验用户是否有访问权限,如果没有则进行拦截。
- 路由和负载均衡:网关根据规则将请求转发到对应的微服务,支持负载均衡。
- 限流:根据下游服务的处理能力,限制请求流量,避免服务崩溃。
# 核心功能特性
稳定性:
- 全局流控、日志统计
- 防止 SQL 注入、Web 攻击
- 黑白名单管理
- 证书、加解密处理
服务级别流控:
- 服务降级与熔断
- 路由与负载均衡、灰度发布
- 服务过滤、权限验证
- 参数校验、多级缓存策略
# Gateway 的架构图
# Gateway 的主要功能
- 权限控制:校验请求的合法性,确保只有有权限的请求才可以访问后端服务。
- 路由和负载均衡:将请求根据路径、请求头等信息路由到相应的服务,支持负载均衡。
- 限流:在高并发场景下,按需控制请求速率,保护后端服务稳定性。
SpringCloud Gateway 是微服务架构中重要的组成部分,通过它,我们可以实现统一的流量管理、服务发现、限流、权限校验等功能。
# 3. Gateway 快速开始
下面我们通过一个简单示例演示 SpringCloud Gateway 的基本路由功能。我们将基于之前搭建的用户服务(UserService)和订单服务(OrderService)进行测试。
# 1. 创建 Gateway 微服务
首先,我们创建一个新的 Spring Boot 项目,命名为 gateway
。
# 2. 引入必要的依赖
在 pom.xml
文件中引入 Gateway 和 Nacos 服务发现的依赖:
<!-- Spring Cloud Gateway 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Nacos 服务发现依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2
3
4
5
6
7
8
9
10
说明:Gateway 依赖提供了网关功能,Nacos 依赖用于服务发现,实现通过服务名称进行负载均衡。
# 3. 编写启动类
在 src/main/java
目录下编写启动类 GateWayApplication
:
package com.example.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.core.env.Environment;
import org.springframework.context.ConfigurableApplicationContext;
/**
* 网关服务启动类
*/
@SpringBootApplication
public class GateWayApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(GateWayApplication.class, args);
Environment environment = context.getBean(Environment.class);
System.out.println("访问链接:http://localhost:" + environment.getProperty("server.port"));
System.out.println("(♥◠‿◠)ノ゙ 项目启动成功 ლ(´ڡ`ლ)゙ \n" +
" .-------. ____ __ \n" +
" | _ _ \\ \\ \\ / / \n" +
" | ( ' ) | \\ _. / ' \n" +
" |(_ o _) / _( )_ .' \n" +
" | (_,_).' __ ___(_ o _)' \n" +
" | |\\ \\ | || |(_,_)' \n" +
" | | \\ `' /| `-' / \n" +
" | | \\ / \\ / \n" +
" ''-' `'-' `-..-' ");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
说明:该启动类为网关服务的入口,Spring Boot 启动时会加载相关配置并启动网关服务。
# 4. 配置路由规则
在 SpringCloud Gateway 中,路由是最核心的配置部分。它决定了请求如何被转发到具体的微服务。我们通过在 src/main/resources/application.yml
文件中定义路由规则来实现这一点。
server:
port: 10010 # 网关服务的端口,用户将通过该端口访问网关
spring:
application:
name: gateway # 网关服务的名称
cloud:
nacos:
server-addr: localhost:8848 # Nacos 服务注册中心的地址
gateway:
routes: # 路由配置列表
- id: userservice # 路由 ID,必须唯一,可自定义命名
uri: lb://userservice # 目标服务地址,lb 代表负载均衡,后跟服务名称
predicates: # 路由断言规则,用于判断请求是否匹配路由
- Path=/user/** # 匹配路径以 /user/ 开头的所有请求
filters: # 路由过滤器,用于在请求和响应之间进行额外处理
- AddRequestHeader=Truth, scholar is freaking awesome! # 添加自定义请求头
- id: orderservice # 另一个路由的 ID,必须唯一
uri: lb://orderservice # 目标服务地址,服务名称为 orderservice
predicates: # 路由断言规则
- Path=/order/** # 匹配路径以 /order/ 开头的所有请求
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
配置项详细说明:
server.port
(必须配置):- 网关服务的端口,所有客户端请求将通过此端口访问网关。
- 例如:
port: 10010
表示网关服务运行在10010
端口。
spring.application.name
(必须配置):- 网关服务的名称,用于服务注册和识别。
- 例如:
name: gateway
是网关服务的名称。
spring.cloud.nacos.server-addr
(必须配置):- Nacos 服务注册中心的地址,用于服务发现和注册。
- 例如:
server-addr: localhost:8848
。
spring.cloud.gateway.routes
(必须配置):网关的路由配置列表,每个路由定义一个转发规则。
路由配置包括以下部分:
id
(必须配置,且唯一):- 路由的唯一标识符,可自定义命名,建议使用有意义的名称,如
userservice
、orderservice
等。 - 例如:
id: userservice
。
- 路由的唯一标识符,可自定义命名,建议使用有意义的名称,如
uri
(必须配置):- 目标服务的地址,支持两种形式:
http://
:用于固定地址的转发,例如http://127.0.0.1:8081
。lb://
:用于负载均衡,后跟服务名称,例如lb://userservice
。这表示通过服务名进行动态负载均衡转发。
- 目标服务的地址,支持两种形式:
predicates
(必须配置):- 路由断言规则,用于匹配请求是否符合条件。常见的断言包括路径、请求头、请求参数等。
- 例如:
- Path=/user/**
表示匹配路径以/user/
开头的所有请求。
filters
(可选配置):- 路由过滤器,用于在请求和响应之间进行处理。常见的过滤器功能包括添加请求头、修改请求参数、响应处理等。
- 例如:
- AddRequestHeader=Truth, scholar is freaking awesome!
添加一个名为Truth
的请求头,值为scholar is freaking awesome!
。
路由规则配置的灵活性
- 路由的
id
可以自定义命名,只要保证唯一即可,建议使用能清晰描述目标服务的名称。 uri
可根据需求选择固定地址或服务名称,通过lb://
来支持负载均衡。predicates
中的路径匹配规则可根据业务需求灵活配置,例如按路径、请求头、参数等进行匹配。filters
是可选项,可以根据需求自定义处理逻辑。
# 5. 测试 Gateway 服务
启动网关服务后,我们访问的是网关的服务端口,而不是具体服务的端口。比如:
在浏览器中访问 http://localhost:10010/user/1
,注意这里 10010
是网关的端口。根据我们在 application.yml
中的配置,符合路径 /user/**
的请求会被网关转发到 userservice
服务。
这意味着,虽然我们访问的是网关的地址,但实际请求会被转发到对应的用户服务(userservice
),并返回用户服务的响应结果:
网关作为统一入口,屏蔽了具体服务的内部实现,客户端只需要与网关交互即可。
# 4. Gateway 路由流程图
为了更清晰理解网关的工作原理,下面是 Gateway 路由的流程图:
# 5. Gateway 使用小结
网关的搭建流程如下:
- 创建项目并引入 Gateway 和 Nacos 服务发现依赖。
- 配置
application.yml
文件,包括服务信息、Nacos 地址和路由规则。 - 通过路由 ID、URI、断言和过滤器配置,实现请求的路由和处理。
路由配置的关键部分:
- 路由 ID:路由的唯一标识。
- URI:路由的目标地址,
http
表示固定地址,lb
表示基于服务名的负载均衡。 - 断言(Predicates):判断请求是否匹配路由规则,如按路径匹配。
- 过滤器(Filters):对请求或响应进行处理,如添加请求头信息。