回顾:没有网关的系统长什么样
经过前面几篇,我们已经有了三个服务:
- Nacos 注册中心 + 配置中心
order-service(端口 8082)payment-service(端口 8081、8083)
每个服务有自己的端口和路径。现在假设前端要来调用,它需要知道:
创建订单:http://{某台机器}:8082/order
发起支付:http://{某台机器}:8081/pay
如果再加一个库存服务(inventory-service,端口 8084),前端又得多记一个地址。更麻烦的是:生产环境中服务实例的 IP 是动态分配的,前端不可能跟着改。
这就是网关的价值——在所有微服务前面放一个统一的入口,外部只和网关打交道,网关负责把请求转发到正确的服务。
Gateway 是什么
Spring Cloud Gateway 是 Spring 体系内的 API 网关实现,底层基于 Reactor 非阻塞模型。它的核心职责只有两个:
- 路由(Route):根据请求的特征(路径、Header、参数等)决定转发给哪个下游服务
- 过滤(Filter):在转发的过程中插入额外的处理逻辑(加请求头、记录日志、鉴权、限流)
一句话概括:外部请求 → Gateway → 根据路由规则选服务 → 经过过滤器链处理 → 转发到目标服务。
核心概念:Route、Predicate、Filter
Gateway 的配置围绕三个概念展开:
| 概念 | 说明 | 类比 |
|---|---|---|
| Route | 一条完整的路由规则,包含目标服务 + 匹配条件 + 过滤器 | 快递路线 |
| Predicate | 断言,判断请求是否匹配这条路由(比如路径以 /order 开头) | 分拣规则 |
| Filter | 对请求或响应做修改(比如添加请求头、限流) | 中转处理 |
一条路由配置长这样:
spring:
cloud:
gateway:
routes:
- id: order-route
uri: lb://order-service
predicates:
- Path=/order/**
filters:
- AddRequestHeader=X-Gateway, true
拆开来看:
id:路由标识,随便起uri: lb://order-service:目标服务,lb://表示走负载均衡,从 Nacos 查order-service的实例predicates:匹配规则,Path=/order/**表示 URL 以/order开头的请求走这条路由filters:过滤器,这里加了一个自定义请求头
动手:搭建 Gateway
新建模块
创建一个新的 Spring Boot 项目 gateway-service。
引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
配置路由
spring:
application:
name: gateway-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
routes:
- id: order-route
uri: lb://order-service
predicates:
- Path=/order/**
- id: payment-route
uri: lb://payment-service
predicates:
- Path=/payment/**
server:
port: 8080
两条路由规则:
/order/**→ 转发到order-service/payment/**→ 转发到payment-service
注意 uri 里用的是 lb:// 前缀,表示通过 Nacos 做服务发现 + 负载均衡。Gateway 和 Nacos 的配合在此刻完全透明。
启动类
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayServiceApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayServiceApplication.class, args);
}
}
验证:统一入口
启动所有服务后,不再直接访问各个服务的端口:
# 旧方式:直接访问服务
curl http://localhost:8082/order
# 新方式:通过网关
curl http://localhost:8080/order
两次返回结果相同:
Order created. Payment successful from port: 8081
再试支付路径:
curl http://localhost:8080/payment/pay
同样正确返回,而且因为负载均衡,多次访问会在 8081 和 8083 之间轮换。
现在前端只需要知道网关的地址(localhost:8080),内部有多少服务、各自在哪个端口、有多少个实例——全部对前端透明。
Filter 简介
Filter 是 Gateway 真正强大的地方。上面的配置里用了一个 AddRequestHeader,这是 Gateway 内置的几十种过滤器之一。常用的还有:
| Filter | 作用 |
|---|---|
AddRequestHeader | 添加请求头 |
AddResponseHeader | 添加响应头 |
PrefixPath | 添加路径前缀 |
StripPrefix | 去掉路径前缀 |
RequestRateLimiter | 请求限流 |
后续讲到 Sentinel 时,我们会在网关层接入 Sentinel 的限流功能——这就是在过滤器链中添加一个 SentinelGatewayFilter。明白了路由 + 过滤这个模型,后续每个组件加入时你都知道它落在哪个位置。
小结与下篇预告
这一篇我们把微服务的对外大门立了起来:
- 理解网关的价值——统一入口,前端不关心内部拓扑
- Route + Predicate + Filter 三要素构成 Gateway 的路由模型
- 动手搭建,两条路由规则将外部请求分发到
order-service和payment-service - Filter 的扩展性——鉴权、日志、限流等横切逻辑都可以在网关层统一处理
现在服务通信链路已经完整了:外部请求 → Gateway → Nacos 发现服务 → LoadBalancer 选实例 → Feign 调用。但这套系统目前有一个盲区:如果 payment-service 突然响应变慢甚至直接挂掉,order-service 还在不断往它发请求,雪崩效应由此开始。
下一篇,我们用 Sentinel 给系统装上保险丝——熔断、降级、限流。