微服务-网关gateway理论与实战
·
网关
概述
网关作用显著,它能作为统一入口,整合后端服务,让客户端无需多次请求。
- 统一入口:整合后端多个服务,客户端只需调用网关提供的唯一接口,无需多次请求不同服务。
- 统一鉴权:集中处理所有服务的身份认证与访问权限控制,无需各服务单独处理。
- 服务发布控制:支持灰度发布等,能灵活控制流量分流到新旧服务,保障服务更新平稳。
- 协议转换:统一处理后端不同协议,对外提供一致的 HTTP 协议接口,简化客户端适配。
- 请求转发:接收客户端请求后,转发到对应的后端服务,还可实现内网与外网隔离。
- 限流、缓存:对请求进行限流,防止系统过载;缓存常用数据,提升响应速度。


鉴权认证

服务发布
灰度发布:新服务上线时,在网关层利用分流引擎

蓝绿发布
将新版本和旧版本都进行部署,然后将新版本上线,利用分流将所有请求换到新版本v2,当出现故障时,直接切回v1即可。

A / B Test
【使用于**测试新系统是否受欢迎**,如果发现不受欢迎则不上新服务】
新服务上线后,设定规则,只有符合规则的才可以访问到新服务(比如设置请求头Header的方法使得安卓用户可访问其他不行)

金丝雀/灰度 发布
刚开始将少量的请求引流到新版本上,然后后续再逐渐引入更多流量

实战
1. 路由匹配规则
- 时间匹配:通过
<font style="color:rgb(0, 0, 0);">Before</font>/<font style="color:rgb(0, 0, 0);">After</font>谓词,根据时间范围转发请求(如指定时间前 / 后路由到特定服务) - Cookie 匹配:
<font style="color:rgb(0, 0, 0);">Cookie</font>谓词,根据请求中是否包含指定 Cookie 键值对进行路由 - Header 匹配:
<font style="color:rgb(0, 0, 0);">Header</font>谓词,检查请求头中是否存在指定键及符合正则的 value(如<font style="color:rgb(0, 0, 0);">X-Request-Id</font>为数字) - Host 匹配:
<font style="color:rgb(0, 0, 0);">Host</font>谓词,根据请求头中的 Host 字段匹配(支持通配符,如<font style="color:rgb(0, 0, 0);">**.muse.com</font>) - 请求方法匹配:
<font style="color:rgb(0, 0, 0);">Method</font>谓词,仅允许指定 HTTP 方法(如 POST)的请求通过 - 路径匹配:
<font style="color:rgb(0, 0, 0);">Path</font>谓词,按 URL 路径匹配(支持通配符,如<font style="color:rgb(0, 0, 0);">/gateway/**</font>)
2. 过滤器功能
- 路径处理:
<font style="color:rgb(0, 0, 0);">StripPrefix</font>,转发前移除路径前缀(如<font style="color:rgb(0, 0, 0);">StripPrefix=1</font>移除第一个路径段) - 参数添加:
<font style="color:rgb(0, 0, 0);">AddRequestParameter</font>,为请求添加固定查询参数(如统一添加<font style="color:rgb(0, 0, 0);">teacher=muse</font>) - 响应头处理:
<font style="color:rgb(0, 0, 0);">AddResponseHeader</font>,为响应添加固定 Header(如<font style="color:rgb(0, 0, 0);">X-Response-Teacher=Muse</font>) - 限流控制:
<font style="color:rgb(0, 0, 0);">RequestRateLimiter</font>,基于令牌桶算法限制请求频率(<font style="color:rgb(0, 0, 0);">replenishRate</font>为令牌填充速度,<font style="color:rgb(0, 0, 0);">burstCapacity</font>为令牌桶容量) - 请求重试:
<font style="color:rgb(0, 0, 0);">Retry</font>,当后端返回指定状态码(如 500)时自动重试(<font style="color:rgb(0, 0, 0);">retries</font>为重试次数) - 指标监控:
<font style="color:rgb(0, 0, 0);">GatewayMetricsFilter</font>,通过配置 management 端点暴露网关监控指标 - 自定义过滤:通过
<font style="color:rgb(0, 0, 0);">name</font>指定自定义过滤器类(需遵循<font style="color:rgb(0, 0, 0);">XXXGatewayFilterFactory</font>命名规范),支持传入自定义参数
server:
port: 8088
# 以下路由只能选一个
#【请求路径匹配路由】
# 请求POST http://localhost:8088/gateway/say会转发http://localhost:8080/say。
spring:
cloud:
gateway:
routes:
- id: path_route
uri: http://localhost:8080 #访问地址
predicates:
- Path=/gateway/** # 路径匹配
filters:
- StripPrefix=1 # StripPrefix参数表示在将请求发送到下游之前从请求中剥离的路径个数。
# 如果我们设置StripPrefix=2时,当通过网关向/gateway/bar/foo 发出请求时,对nameservice的请求将类似于/foo。
#【指定时间规则匹配路由】
# 在2027-01-01 00:00:00之前访问的请求,都会转到http://localhost:8080,、
# 即:http://localhost:8088/say会转发到http://localhost:8080/say
spring:
cloud:
gateway:
routes:
- id: before_route
uri: http://localhost:8080 # 目标服务地址,请求最终转发的目的地
predicates: # 只有当请求满足该路由的所有谓词条件时,才会触发路由转发。
- Before=2027-01-01T00:00:00.000+08:00 # 即请求是符合再2027-01-01之前发送的,就符合该网关的转发,可以转发
#【指定时间规则匹配路由】
#在2021-01-01 00:00:00之后访问的请求,都会转到http://localhost:8080,即:http://localhost:8088/say会转发到http://localhost:8080/say
spring:
cloud:
gateway:
routes:
- id: after_route
uri: http://localhost:8080
predicates:
- After=2021-01-01T00:00:00.000+08:00
#【指定Cookie规则匹配路由】
#请求配置localhost的Cookie(chocolate=mic;) 请求http://localhost:8088/say会转发到http://localhost:8080/say
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: http://localhost:8080
predicates:
- Cookie=chocolate, mic # 即需要cookie中 chocolate = mic
#【指定Header规则匹配路由】
#请求配置Header(key=X-Request-Id value=1) 请求http://localhost:8088/say会转发到http://localhost:8080/say
spring:
cloud:
gateway:
routes:
- id: header_route
uri: http://localhost:8080
predicates:
- Header=X-Request-Id, \d+
#【指定Host规则匹配路由】
#请求配置Header(Host:www.muse.com) 请求http://localhost:8088/say会转发到http://localhost:8080/say
spring:
cloud:
gateway:
routes:
- id: host_route
uri: http://localhost:8080
predicates:
- Host=**.muse.com
#【请求方法匹配路由】
# 请求POST http://localhost:8088/shout会转发http://localhost:8080/shout。请求GET http://localhost:8088/say 会报"404 Not Found"
spring:
cloud:
gateway:
routes:
- id: method_route
uri: http://localhost:8080 #访问地址
predicates:
- Method=POST
#【请求路径匹配路由】
# 请求POST http://localhost:8088/gateway/say会转发http://localhost:8080/say。
spring:
cloud:
gateway:
routes:
- id: path_route
uri: http://localhost:8080 #访问地址
predicates:
- Path=/gateway/** #路径匹配
filters:
- StripPrefix=1 #StripPrefix参数表示在将请求发送到下游之前从请求中剥离的路径个数。如果我们设置StripPrefix=2时,当通过网关向/gateway/bar/foo
# 发出请求时,对nameservice的请求将类似于/foo。
#【添加request查询参数过滤器】
#会对所有请求增加teacher=muse这个参数
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: http://localhost:8080 #访问地址
predicates:
- Path=/**
filters:
- AddRequestParameter=teacher, muse
#【添加response响应Header参数过滤器】
#返回结果给客户端之前,在Header中添加相应的数据
spring:
cloud:
gateway:
routes:
- id: add_response_header_route
uri: http://localhost:8080 #访问地址
predicates:
- Path=/**
filters:
- AddResponseHeader=X-Response-Teacher, Muse
#【添加限流过滤器】
spring:
cloud:
gateway:
routes:
- id: request_ratelimiter_route
uri: http://localhost:8080 #访问地址
predicates:
- Path=/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1 #令牌桶中令牌的填充速度,代表允许每秒执行的请求数
redis-rate-limiter.burstCapacity: 1 #令牌桶的容量,也就是令牌桶最多能够容纳的令牌数。表示每秒用户最大能够执行的请求数量
redis:
host: 127.0.0.1
port: 6379
#【添加请求重试过滤器】
spring:
cloud:
gateway:
routes:
- id: retry_route
uri: http://localhost:8080
predicates:
- Path=/example/**
filters:
- name: Retry
args:
retries: 3 #请求重试次数,默认值是3
status: 500 #HTTP请求返回的状态码,针对指定状态码进行重试。
- StripPrefix=1
#【网关指标过滤器——GatewayMetricsFilter】
management:
endpoint:
gateway:
enabled: true
endpoints:
web:
exposure:
include: "*"
自定义过滤器
#【请求路径匹配路由——配置自定义过滤器】
spring:
cloud:
gateway:
routes:
- id: define_filter
uri: http://localhost:8080 #访问地址
predicates:
- Path=/gateway/** #路径匹配
filters:
- name: GpDefine # 自定义过滤器的名字,即:GpDefineGatewayFilterFactory
args:
name: Gp_Mic #GpConfig.getName这个值
- StripPrefix=1 #跳过前缀
自定义过滤器:类名必须命名为 xxGatewayFilterFactory
xx 即为 name,这个 name 需要到 yaml 中配置,该过滤器才会生效【如下面的GpDefine】
作用与使用场景:
- 作用:仅对配置了该过滤器的路由生效,实现路由级别的个性化处理。
- 使用场景:
- 特定路由的日志记录(如支付路由单独记录请求参数)。
- 路由级别的参数校验(如仅对用户路由验证 token 格式)。
- 路由专属的响应加工(如对商品路由的响应添加促销标签)。
package com.muse.gatewaysample;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
/**
* 自定义路由级别GatewayFilter
* 注意:
* 1. 类名必须以GatewayFilterFactory结尾,前缀(GpDefine)作为过滤器在yaml中的引用名称
* 2. 需继承AbstractGatewayFilterFactory,泛型指定配置类类型
* 3. 通过@Service注解注册到Spring容器中
*/
@Service
public class GpDefineGatewayFilterFactory extends AbstractGatewayFilterFactory<GpDefineGatewayFilterFactory.GpConfig> {
/**
* 构造方法:必须调用父类构造器,传入配置类Class对象
* 用于告诉父类当前过滤器使用哪个配置类解析yaml参数
*/
public GpDefineGatewayFilterFactory() {
super(GpConfig.class);
}
/**
* 核心方法:实现过滤逻辑
* @param config 配置类对象,包含从yaml中读取的参数
* @return GatewayFilter 过滤器实例
*/
@Override
public GatewayFilter apply(GpConfig config) {
// 返回一个GatewayFilter函数式接口实现
return ((exchange, chain) -> {
// 【前置过滤逻辑】:在请求转发到后端服务之前执行
// exchange包含请求和响应对象,可获取/修改请求参数、头信息等
System.out.println("GpDefineGatewayFilterFactory [Pre] Filter Request, config.getName() = " + config.getName());
// 继续执行过滤器链,chain.filter(exchange)会将请求传递给下一个过滤器
// then()方法中的逻辑会在后端服务响应后执行(后置处理)
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
// 【后置过滤逻辑】:在后端服务返回响应后、响应给客户端之前执行
System.out.println("GpDefineGatewayFilterFactory [Post] Response Filter");
}));
});
}
/**
* 自定义配置类:用于接收yaml中配置的过滤器参数
* 配置类的属性会与yaml中args下的参数自动绑定
*/
public static class GpConfig {
// 示例参数:name
private String name;
// 必须提供getter和setter方法,否则无法完成参数绑定
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
全局过滤器(GpdefineFilter)
去实现了全局过滤器,每个请求都会经过这个,无需配置即可使用(使用场景)
特点(与自定义过滤器的核心区别)
- 无需 YAML 配置:所有请求都会经过,不依赖路由配置。
- 全局生效:无论匹配哪个路由,都会执行该过滤器。
作用与使用场景
- 作用:对整个网关的所有请求 / 响应进行统一处理。
- 使用场景:
- 全局鉴权(如验证所有请求的 token 是否存在)。
- 全局限流(如限制所有请求的 QPS)。
- 全局日志收集(记录所有请求的 URL、耗时等)。
- 跨域处理(统一配置 CORS 规则)。
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component // 注册到容器
public class GpDefineFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, org.springframework.cloud.gateway.filter.GatewayFilterChain chain) {
// 前置处理:所有请求都会经过这里(如全局鉴权)
System.out.println("GlobalFilter [Pre] 全局前置处理");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
// 后置处理:所有响应返回前都会经过这里(如全局响应日志)
System.out.println("GlobalFilter [Post] 全局后置处理");
}));
}
@Override
public int getOrder() {
return 0; // 执行顺序(0优先于1)
}
}
nacos集成gateway
作用和使用场景Nacos 作为注册中心和配置中心,与 Gateway 集成的核心价值是 实现服务的动态发现、路由管理和配置动态更新,解决网关对后端服务的动态适配问题。
具体体现:
- 服务发现与动态路由:Gateway 通过 Nacos 自动感知后端服务(Provider)的注册、下线、地址变更,无需手动修改路由的
uri配置。 - 负载均衡:结合
lb://服务名路由格式,Gateway 可基于 Nacos 提供的服务列表实现请求的负载均衡(如轮询、权重等)。 - 配置动态刷新:若网关路由规则配置在 Nacos 配置中心,修改后可实时生效,无需重启网关服务。
使用场景
- 微服务架构中的服务路由:当系统存在多个后端服务(如用户服务、订单服务),且服务实例会动态扩缩容时,通过 Nacos 让 Gateway 自动发现服务并转发请求。
- 多环境适配:开发、测试、生产环境的服务地址不同,通过 Nacos 统一管理服务注册,Gateway 无需修改配置即可适配不同环境。
- 灰度发布 / 蓝绿部署:配合 Nacos 的权重配置,Gateway 可将部分流量路由到新版本服务实例,实现平滑更新。
需要nacos-gateway-provider(作为转发的地址)、nacos-gateway-consumer(作为直接地址)
1.consumer-yaml
server:
port: 8888 # Consumer端端口(网关服务运行端口,客户端通过此端口访问网关)
spring:
application:
name: gateway-nacos-consumer # 服务名(注册到Nacos的名称,用于标识网关服务)
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # Nacos注册中心地址(网关服务需注册到Nacos,才能发现Provider服务)
gateway:
discovery:
locator:
enabled: true # 开启「从Nacos注册中心动态创建路由」的功能(无需手动配置每个Provider路由,可通过服务名访问)
lower-case-service-id: true # 允许使用小写的服务名访问(默认服务名是大写,开启后可通过 http://网关IP:端口/服务名/接口 访问)
routes: # 手动配置的路由规则(优先级高于动态路由)
- id: gateway-nacos-provider # 路由唯一标识(自定义,需唯一)
uri: lb://gateway-nacos-provider # 路由目标地址:lb=Load Balance(负载均衡),后面跟Provider在Nacos的服务名
predicates: # 路由匹配条件(满足才触发此路由)
- Path=/nacos/** # 路径匹配:客户端请求路径以 /nacos 开头时,触发此路由
filters: # 路由过滤器(对请求/响应做加工)
- StripPrefix=1 # 移除路径前缀1级:如请求 /nacos/sayHello → 转发给Provider时路径变为 /sayHello
2.provider-yaml
server:
port: 8080 # Provider端端口(业务服务运行端口,处理实际业务逻辑)
spring:
application:
name: gateway-nacos-provider # 服务名(注册到Nacos的名称,Consumer端通过此名发现该服务)
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # Nacos注册中心地址(将Provider服务注册到Nacos,供网关发现)
package com.muse.gateway.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Provider端业务控制器:处理客户端通过网关转发过来的请求
*/
@RestController // 标识此类为REST接口控制器(返回JSON数据,无页面)
public class NacosController {
// 从配置文件中读取 server.port 属性值(即当前Provider服务的运行端口)
@Value("${server.port}")
private int port;
/**
* 业务接口:处理GET请求,返回带端口的问候信息
* 访问路径:Provider端原生路径是 /sayHello,通过网关访问时需加前缀 /nacos(对应Consumer路由配置)
*/
@GetMapping("/sayHello") // 映射GET请求到 /sayHello 路径
public String sayHello() {
// 控制台打印日志(用于调试,确认请求到达Provider)
System.out.println("[gateway-nacos-provider]: sayHello");
// 返回响应结果(包含端口,方便区分多实例部署时的负载均衡效果)
return "[gateway-nacos-provider]: sayHello port=" + port;
}
}
Sentinel 集成 Gateway 实现
作用和使用场景核心作用
Sentinel 作为流量治理工具,与 Gateway 集成的核心价值是 对网关层的请求进行流量控制、熔断降级和监控,保护后端服务不被流量冲击。
具体体现:
- 网关层限流:基于路由、路径、参数等维度限制 QPS(如限制
/api/order/**路径每秒最多 100 个请求)。 - 熔断降级:当后端服务响应缓慢或异常时,Sentinel 可触发熔断,直接返回降级响应(如 “服务繁忙”),避免请求堆积拖垮服务。
- 流量监控:通过 Sentinel 控制台实时查看网关的请求量、限流次数、响应时间等指标,便于问题排查。
使用场景
- 高并发接口保护:针对秒杀、促销等场景的核心接口(如
/api/seckill/**),通过限流防止流量超过服务承载能力。 - 服务稳定性保障:当后端服务出现异常(如数据库超时),通过熔断机制快速失败,避免网关持续转发无效请求。
- 流量监控与告警:实时监控网关流量趋势,当请求量突增或限流频繁时,通过 Sentinel 告警及时介入处理。
二、代码与配置
1. 公共依赖(两个服务都需要)
xml
<!-- pom.xml 核心依赖 -->
<dependencies>
<!-- 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>
<!-- Sentinel 集成 Gateway -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<!-- Sentinel 核心包 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
</dependencies>
2. Provider 端(sentinel-gateway-provider,业务服务)
(1)application.yml 配置
server:
port: 8080 # Provider服务端口
spring:
application:
name: sentinel-gateway-provider # 服务名(注册到Nacos的标识)
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # Nacos注册中心地址(可选,不使用注册中心可删除)
(2)业务控制器(ProviderController.java)
package com.muse.sentinel.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Provider业务接口:处理网关转发的请求
*/
@RestController
public class ProviderController {
// 注入当前服务端口,用于区分实例
@Value("${server.port}")
private int port;
/**
* 测试接口:返回带端口的响应
*/
@GetMapping("/test")
public String test() {
System.out.println("Provider接收请求,端口:" + port);
return "Provider响应 [port=" + port + "]";
}
}
3. Consumer 端(sentinel-gateway-consumer,网关服务)
(1)application.yml 配置
yaml
server:
port: 8888 # 网关服务端口(客户端访问入口)
spring:
application:
name: sentinel-gateway-consumer # 网关服务名
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # Nacos地址(可选)
gateway:
routes:
- id: provider_route # 路由唯一标识
uri: lb://sentinel-gateway-provider # 转发目标(lb=负载均衡,服务名对应Provider)
predicates:
- Path=/api/** # 匹配路径:客户端访问/api/** 时触发此路由
filters:
- StripPrefix=1 # 移除1级前缀:/api/test → 转发为/test
sentinel:
transport:
dashboard: 127.0.0.1:8080 # Sentinel控制台地址(需单独启动)
port: 8719 # 本地与Sentinel控制台通信的端口(默认8719,如被占用自动+1)
scg:
fallback:
mode: response # 限流/熔断后的降级模式(response=返回固定响应)
response-body: "请求过于频繁,请稍后再试!" # 降级响应内容
(2)网关配置类(SentinelGatewayConfig.java)
package com.muse.sentinel.config;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashSet;
import java.util.Set;
/**
* Sentinel网关配置:注册过滤器并初始化限流规则
*/
@Configuration
public class SentinelGatewayConfig {
/**
* 注册Sentinel全局过滤器:所有请求都会经过此过滤器,实现限流/熔断
*/
@Bean
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
/**
* 初始化Sentinel限流规则(也可通过Sentinel控制台动态配置)
*/
public void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();
// 为路由id=provider_route设置限流规则
rules.add(new GatewayFlowRule("provider_route")
.setCount(2) // 限流阈值:每秒最多2个请求
.setIntervalSec(1) // 统计时间窗口(秒)
);
// 将规则加载到Sentinel
GatewayRuleManager.loadRules(rules);
}
}
更多推荐




所有评论(0)