Gateway 网关
一、Gateway 概述
网关职责
┌─────────────────────────────────────────────────────────────────┐
│ Gateway 网关 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 路由转发 │ │
│ │ │ │
│ │ /api/user/** ──────▶ user-service:8080 │ │
│ │ /api/order/** ──────▶ order-service:8081 │ │
│ │ /api/pay/** ──────▶ payment-service:8082 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 过滤器链 │ │
│ │ │ │
│ │ 请求 ──▶ 认证 ──▶ 限流 ──▶ 路由 ──▶ 日志 ──▶ 响应 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 功能:路由转发 / 认证鉴权 / 限流熔断 / 日志监控 / 协议转换 │
│ │
└─────────────────────────────────────────────────────────────────┘WebFlux vs Servlet
┌─────────────────────────────────────────────────────────────────┐
│ Gateway 基于 WebFlux │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Spring WebFlux = Reactive + Non-Blocking │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Spring MVC │ │ Spring WebFlux │ │
│ ├──────────────────┤ ├──────────────────┤ │
│ │ Servlet API │ │ Reactive Streams │ │
│ │ 同步阻塞 │ │ 异步非阻塞 │ │
│ │ Tomcat/Jetty │ │ Netty/Reactor │ │
│ │ 一请求一线程 │ │ 事件驱动 │ │
│ └──────────────────┘ └──────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘二、快速开始
Maven 依赖
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>基础配置
yaml
spring:
cloud:
gateway:
routes:
- id: user-route
uri: http://localhost:8080
predicates:
- Path=/api/user/**
filters:
- StripPrefix=1三、路由配置
完整路由配置
yaml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: http://localhost:8080
predicates:
- Path=/api/user/**
- Method=GET,POST
- Header=X-Request-Id, \d+
- Query=name, zhang.*
filters:
- StripPrefix=1
order: 1 # 路由优先级,数字越小优先级越高Java DSL 配置
java
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("user-service", r -> r
.path("/api/user/**")
.filters(f -> f
.stripPrefix(1)
.addRequestHeader("X-Gateway", "true")
)
.uri("http://localhost:8080")
)
.route("order-service", r -> r
.path("/api/order/**")
.filters(f -> f
.stripPrefix(1)
.retry(retry -> retry
.retries(3)
.statuses(HttpStatus.INTERNAL_SERVER_ERROR)
)
)
.uri("http://localhost:8081")
)
.build();
}
}动态路由(Nacos)
yaml
spring:
cloud:
gateway:
routes:
- id: user-service
# 使用 lb:// 前缀启用负载均衡
uri: lb://user-service
predicates:
- Path=/api/user/**
filters:
- StripPrefix=1
# 自动从 Nacos 获取 user-service 的实例列表
# 并进行负载均衡四、断言(Predicate)
常用断言
yaml
spring:
cloud:
gateway:
mvc:
predicates:
# 1. Path 路径断言(最常用)
- Path=/api/user/**
# 2. Method 方法断言
- Method=GET,POST
# 3. Header 头断言
- Header=X-Request-Id, \d+
# 4. Query 参数断言
- Query=name, zhang.*
# 5. Cookie 断言
- Cookie=session, abc.*
# 6. Host 主机断言
- Host=**.example.com
# 7. 远程地址断言
- RemoteAddr=192.168.1.0/24
# 8. 时间断言(用于版本控制)
- After=2024-01-01T00:00:00+08:00[Asia/Shanghai]
- Before=2024-12-31T23:59:59+08:00[Asia/Shanghai]
- Between=2024-01-01T00:00:00+08:00[Asia/Shanghai],2024-12-31T23:59:59+08:00[Asia/Shanghai]组合断言
yaml
spring:
cloud:
gateway:
routes:
- id: complex-route
uri: http://localhost:8080
predicates:
# AND 关系:所有条件都满足
- Path=/api/user/**
- Method=GET
- Header=X-Request-Id, \d+五、过滤器(Filter)
过滤器类型
┌─────────────────────────────────────────────────────────────────┐
│ Gateway 过滤器 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Gateway Filter │ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ Global Filter │ │ Route Filter │ │ │
│ │ │ 全局过滤器 │ │ 路由过滤器 │ │ │
│ │ │ 所有路由生效 │ │ 指定路由生效 │ │ │
│ │ └─────────────────┘ └─────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 执行顺序: │
│ 1. 所有 GatewayFilter 按 order 排序 │
│ 2. 所有 GlobalFilter 按 order 排序 │
│ 3. 组合后的过滤器链顺序执行 │
│ │
└─────────────────────────────────────────────────────────────────┘内置过滤器
yaml
spring:
cloud:
gateway:
routes:
- id: filter-demo
uri: http://localhost:8080
filters:
# 1. StripPrefix 去除前缀
- StripPrefix=1
# 2. PrefixPath 添加前缀
- PrefixPath=/api
# 3. AddRequestHeader 添加请求头
- AddRequestHeader=X-Gateway, true
# 4. AddRequestParameter 添加请求参数
- AddRequestParameter=name, zhangsan
# 5. AddResponseHeader 添加响应头
- AddResponseHeader=X-Response-Gateway, true
# 6. RemoveRequestHeader 移除请求头
- RemoveRequestHeader=X-Request-Id
# 7. RemoveResponseHeader 移除响应头
- RemoveResponseHeader=Server
# 8. SetStatus 设置状态码
- SetStatus=UNAUTHORIZED
# 9. RedirectTo 重定向
- RedirectTo=302, https://example.com
# 10. Retry 重试
- name: Retry
args:
retries: 3
statuses: INTERNAL_SERVER_ERROR
# 11. RequestRateLimiter 限流
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20SetStatus 示例
yaml
spring:
cloud:
gateway:
routes:
- id: auth-route
uri: http://localhost:8080
filters:
# 401 响应
- SetStatus=401
# 自定义状态码
- SetStatus=UNAUTHORIZED六、全局过滤器
自定义全局过滤器
java
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
private final Logger log = LoggerFactory.getLogger(getClass());
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (StringUtils.isBlank(token)) {
log.warn("Token is missing");
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 验证 token
if (!validateToken(token)) {
log.warn("Invalid token");
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 验证通过,继续
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -100; // 执行顺序,数字越小越先执行
}
}常用全局过滤器
java
// 1. LoadBalancerClientFilter(负载均衡)
// 2. NettyRoutingFilter(路由转发)
// 3. WebClientHttpRoutingFilter(响应式路由)
// 4. RouteToRequestUrlFilter(URL 转换)组合过滤器执行顺序
┌─────────────────────────────────────────────────────────────────┐
│ 过滤器执行顺序 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. 所有过滤器按 order 排序 │
│ 2. 负数 order 的过滤器先执行 │
│ 3. 执行 pre 过滤器 │
│ 4. 执行目标服务 │
│ 5. 执行 post 过滤器(倒序) │
│ │
│ 示例: │
│ - GlobalA (order=-1) │
│ - GlobalB (order=0) │
│ - RouteFilter1 (order=1) │
│ - RouteFilter2 (order=2) │
│ │
│ 执行顺序:GlobalA → GlobalB → RouteFilter1 → RouteFilter2 │
│ → RouteFilter2 → RouteFilter1 → GlobalB → GlobalA │
│ │
└─────────────────────────────────────────────────────────────────┘七、限流
Redis 限流
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>yaml
spring:
cloud:
gateway:
routes:
- id: rate-limit-route
uri: http://localhost:8080
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 # 每秒允许请求数
redis-rate-limiter.burstCapacity: 20 # 桶容量
redis-rate-limiter.requestedTokens: 1 # 每个请求消耗令牌自定义限流 Key
java
@Component
public class KeyResolver implements KeyResolver {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
// 方式1:按 IP 限流
String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
return Mono.just(ip);
// 方式2:按用户限流
// String userId = exchange.getPrincipal().map(Principal::getName).block();
// return Mono.just(userId);
// 方式3:按路径限流
// String path = exchange.getRequest().getPath().value();
// return Mono.just(path);
}
}yaml
spring:
cloud:
gateway:
routes:
- id: rate-limit-route
uri: http://localhost:8080
filters:
- name: RequestRateLimiter
args:
key-resolver: '#{@pathKeyResolver}' # 引用 Bean
redis-rate-limiter.replenishRate: 100
redis-rate-limiter.burstCapacity: 200八、CORS 配置
java
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOriginPattern("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.setAllowCredentials(true);
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(
new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}yaml
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOriginPatterns: "*"
allowedHeaders: "*"
allowedMethods: "*"
allowCredentials: true
maxAge: 3600九、高可用
架构
┌─────────────────┐
│ Nginx │
│ (负载均衡) │
└────────┬────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
┌────┴────┐ ┌────┴────┐ ┌────┴────┐
│Gateway-1│ │Gateway-2│ │Gateway-3│
│ :8080 │ │ :8080 │ │ :8080 │
└─────────┘ └─────────┘ └─────────┘Nginx 配置
nginx
upstream gateway {
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080;
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://gateway;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}十、面试高频问题
Q1: Gateway 和 Zuul 区别?
| 对比 | Zuul | Gateway |
|---|---|---|
| 线程模型 | 同步阻塞 | 响应式非阻塞 |
| 技术栈 | Servlet | WebFlux |
| 性能 | 一般 | 更高 |
| 维护 | 已停止 | 活跃 |
Q2: 过滤器执行顺序?
- 按 order 排序(全局/路由)
- 负数先执行
- pre → 路由 → post(倒序)
Q3: 如何实现认证?
java
@Component
public class AuthFilter implements GlobalFilter {
@Override
public Mono<Void> filter(...) {
// 1. 提取 Token
// 2. 验证 Token
// 3. 放行或拒绝
}
}Q4: 动态路由如何实现?
配置 lb://service-name,Gateway 会从 Nacos/Eureka 获取服务实例列表并负载均衡
十一、下一章预告
下一章我们将学习 Spring 高级特性:
- 三级缓存与循环依赖
- Bean 生命周期
- 动态代理与 AOP 原理
- 事务传播行为