Spring Cloud Alibaba Gateway 实战教学:构建高性能微服务网关
本教程从零开始,带你完整掌握 Spring Cloud Alibaba Gateway 的核心用法,包括路由、断言、过滤器、Nacos 集成、JWT 鉴权、限流、跨域、熔断降级等实战技能。
1. 核心概念
Spring Cloud Gateway 是基于 Spring WebFlux + Project Reactor + Netty 构建的 API 网关,不依赖 Servlet 容器,性能远超早期的 Zuul。
三大核心组件
|
组件 |
作用 |
类比 |
|---|---|---|
|
Route(路由) |
网关的基本构建块,包含 ID、目标 URI、断言和过滤器 |
一条转发规则 |
|
Predicate(断言) |
匹配条件,决定请求是否进入该路由 |
if 条件判断 |
|
Filter(过滤器) |
在请求前/后对请求和响应进行修改 |
拦截器 |
请求处理流程
客户端请求
│
▼
Gateway Handler Mapping ← 根据 Predicate 匹配路由
│
▼
Gateway Web Handler ← 执行过滤器链
│
├── Pre Filter(前置过滤) ← 鉴权、日志、限流等
│
├── 代理请求到下游服务
│
└── Post Filter(后置过滤) ← 修改响应头、统一异常处理
│
▼
返回客户端响应
两种 URI 协议
uri: https://example.org # 直接转发到固定地址
uri: lb://user-service # 结合负载均衡转发到注册中心的服务
2. 项目搭建
2.1 创建 Maven 项目
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>gateway-service</artifactId>
<version>1.0.0</version>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2023.0.1</spring-cloud.version>
<spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 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>
<!-- Nacos 配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- 负载均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!-- 限流:基于 Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.12.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.12.5</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.2 启动类
package com.example.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
Loading...(GatewayApplication.class, args);
}
}
2.3 基础配置文件
# application.yml
server:
port: 8080
spring:
application:
name: gateway-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: dev
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
namespace: dev
gateway:
# 基础路由配置(后面会逐步扩展)
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**
关键提醒: Gateway 基于 WebFlux,不能引入 spring-boot-starter-web,否则启动冲突。
3. 路由配置详解
3.1 配置文件方式(推荐)
spring:
cloud:
gateway:
routes:
# 用户服务
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**
filters:
- StripPrefix=1 # 去掉第一层路径前缀,/api/user/list -> /user/list
# 订单服务
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/order/**
filters:
- StripPrefix=1
# 直接转发到外部地址
- id: baidu-route
uri: 百度一下,你就知道
predicates:
- Path=/search/**
3.2 Java DSL 方式
适合需要动态、编程式配置的场景:
package com.example.gateway.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RouteConfig {
@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("lb://user-service"))
// 订单服务路由
.route("order-service", r -> r
.path("/api/order/**")
.filters(f -> f.stripPrefix(1))
.uri("lb://order-service"))
// 基于 Host 的路由
.route("host-route", r -> r
.host("*.example.com")
.uri("lb://host-service"))
.build();
}
}
3.3 StripPrefix 详解
这是最常用的过滤器之一,理解它非常重要:
原始请求: /api/user/profile
│ 配置: StripPrefix=1
│ 转发后: /user/profile ← 去掉了 /api 这一层 配置: StripPrefix=2
│ 转发后: /profile ← 去掉了 /api/user 两层
4. 断言(Predicate)全览
断言决定请求是否匹配某条路由,多个断言之间是 AND 关系(全部满足才匹配)。
4.1 常用断言一览
|
断言 |
示例 |
说明 |
|---|---|---|
|
Path |
Path=/api/user/** |
路径匹配(最常用) |
|
Method |
Method=GET,POST |
HTTP 方法匹配 |
|
Header |
Header=X-Request-Id, \d+ |
请求头匹配(支持正则) |
|
Host |
Host=**.example.com |
Host 头匹配 |
|
Query |
Query=token, .+ |
查询参数匹配 |
|
Cookie |
Cookie=session, .+ |
Cookie 匹配 |
|
After |
After=2025-01-01T00:00:00+08:00 |
指定时间之后 |
|
Before |
Before=2025-12-31T23:59:59+08:00 |
指定时间之前 |
|
Between |
Between=start, end |
时间区间内 |
|
RemoteAddr |
RemoteAddr=192.168.1.0/24 |
IP 地址匹配 |
|
Weight |
Weight=group1, 8 |
权重分流 |
4.2 组合断言示例
spring:
cloud:
gateway:
routes:
# 组合条件:路径 + 方法 + 请求头
- id: combined-route
uri: lb://order-service
predicates:
- Path=/api/order/**
- Method=GET,POST
- Header=X-Request-Id, \d+
- Query=userId, .+
# 时间窗口路由(灰度发布场景)
- id: time-window-route
uri: lb://promotion-service
predicates:
- Path=/api/promotion/**
- Between=2025-11-11T00:00:00+08:00, 2025-11-12T00:00:00+08:00
# 权重路由(金丝雀发布:90% 流量到 v1,10% 到 v2)
- id: weight-v1
uri: lb://user-service-v1
predicates:
- Path=/api/user/**
- Weight=user-group, 90
- id: weight-v2
uri: lb://user-service-v2
predicates:
- Path=/api/user/**
- Weight=user-group, 10
4.3 自定义断言
package com.example.gateway.predicate;
import jakarta.validation.constraints.NotEmpty;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import java.util.function.Predicate;
@Component
public class AgeRoutePredicateFactory
extends AbstractRoutePredicateFactory<AgeRoutePredicateFactory.Config> {
public AgeRoutePredicateFactory() {
super(Config.class);
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return exchange -> {
String age = exchange.getRequest().getHeaders().getFirst("X-User-Age");
if (age == null) return false;
return Integer.parseInt(age) >= config.getMinAge();
};
}
@Override
public List<String> shortcutFieldOrder() {
return List.of("minAge");
}
public static class Config {
@NotEmpty
private int minAge;
public int getMinAge() { return minAge; }
public void setMinAge(int minAge) { this.minAge = minAge; }
}
}
配置使用:
spring:
cloud:
gateway:
routes:
- id: age-route
uri: lb://adult-service
predicates:
- Path=/api/adult/**
- Age=18 # 自定义断言:X-User-Age >= 18
5. 过滤器(Filter)详解
5.1 两大类型
|
类型 |
作用范围 |
典型用途 |
|---|---|---|
|
GatewayFilter |
仅对配置了该过滤器的路由生效 |
路径重写、添加请求头 |
|
GlobalFilter |
对所有路由生效 |
JWT 鉴权、全局日志、限流 |
5.2 常用内置 GatewayFilter
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**
filters:
# 路径处理
- StripPrefix=1 # 去掉前缀层
- PrefixPath=/api/v1 # 添加前缀
# 请求头操作
- AddRequestHeader=X-Gateway-Name, gateway-service
- AddRequestParameter=source, gateway
- RemoveRequestHeader=X-Internal-Token
- SetRequestHeader=Content-Type, application/json
# 响应头操作
- AddResponseHeader=X-Response-From, gateway
- SetStatus=200
# 重试
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY, GATEWAY_TIMEOUT
methods: GET
backoff:
firstBackoff: 100ms
maxBackoff: 500ms
factor: 2
# 请求大小限制
- name: RequestSize
args:
maxSize: 10MB
5.3 默认过滤器(作用于所有路由)
spring:
cloud:
gateway:
default-filters:
- AddRequestHeader=X-Gateway, gateway-service
- AddResponseHeader=X-Response-Time, ${spring.application.name}
5.4 过滤器执行顺序
@Component
@Order(-100) // 先执行
public class AuthFilter implements GlobalFilter { ... }
@Component
@Order(0) // 中间执行
public class LogFilter implements GlobalFilter { ... }
@Component
@Order(100) // 后执行
public class ResponseFilter implements GlobalFilter { ... }
规则: 优先执行鉴权过滤器(最先),然后是日志/限流,最后是响应处理。系统保留 -10000 ~ 10000 范围,自定义过滤器建议用该范围内的值。
6. Nacos 服务发现集成
6.1 自动路由
开启后,Gateway 会自动为 Nacos 中注册的每个服务创建路由:
spring:
cloud:
gateway:
discovery:
locator:
enabled: true # 开启自动路由
lower-case-service-id: true # 服务名转小写
开启后可直接访问:http://localhost:8080/USER-SERVICE/user/list
6.2 手动路由(推荐生产使用)
自动路由粒度太粗,生产环境推荐手动配置,精确控制:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service # lb:// 前缀触发负载均衡
predicates:
- Path=/api/user/**
filters:
- StripPrefix=1
6.3 Nacos 动态路由(热更新)
通过 Nacos 配置中心实现路由表热更新,无需重启网关:
package com.example.gateway.config;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import jakarta.annotation.PostConstruct;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
@Component
public class NacosDynamicRouteListener {
private final NacosConfigManager configManager;
private final ApplicationEventPublisher publisher;
private final RouteDefinitionLocator routeDefinitionLocator;
private static final String ROUTE_DATA_ID = "gateway-routes.json";
private static final String GROUP = "DEFAULT_GROUP";
public NacosDynamicRouteListener(NacosConfigManager configManager,
ApplicationEventPublisher publisher,
RouteDefinitionLocator routeDefinitionLocator) {
this.configManager = configManager;
this.publisher = publisher;
this.routeDefinitionLocator = routeDefinitionLocator;
}
@PostConstruct
public void init() {
try {
// 获取当前路由配置
String config = configManager.getConfigService()
.getConfigAndSignListener(ROUTE_DATA_ID, GROUP, 5000);
// 添加配置变更监听
configManager.getConfigService().addListener(ROUTE_DATA_ID, GROUP, new Listener() {
@Override
public Executor getExecutor() {
return null; // 使用默认线程
}
@Override
public void receiveConfigInfo(String configInfo) {
// 配置变更时,发布事件触发路由刷新
publisher.publishEvent(new RefreshRoutesEvent(this));
}
});
} catch (Exception e) {
throw new RuntimeException("初始化动态路由失败", e);
}
}
}
在 Nacos 中创建 gateway-routes.json 配置:
[
{
"id": "user-service",
"uri": "lb://user-service",
"predicates": [
{ "name": "Path", "args": { "pattern": "/api/user/**" } }
],
"filters": [
{ "name": "StripPrefix", "args": { "parts": "1" } }
],
"order": 0
},
{
"id": "order-service",
"uri": "lb://order-service",
"predicates": [
{ "name": "Path", "args": { "pattern": "/api/order/**" } }
],
"filters": [
{ "name": "StripPrefix", "args": { "parts": "1" } }
],
"order": 1
}
]
7. 自定义全局过滤器:JWT 鉴权
这是网关最重要的实战功能之一——统一鉴权,避免每个微服务单独处理认证。
7.1 JWT 工具类
package com.example.gateway.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import javax.crypto.SecretKey;
public class JwtUtil {
private static final String SECRET = "your-256-bit-secret-key-must-be-at-least-32-chars";
private static final SecretKey KEY = Keys.hmacShaKeyFor(SECRET.getBytes());
public static Claims parseToken(String token) {
return Jwts.parser()
.verifyWith(KEY)
.build()
.parseSignedClaims(token)
.getPayload();
}
public static boolean validateToken(String token) {
try {
parseToken(token);
return true;
} catch (Exception e) {
return false;
}
}
}
7.2 鉴权全局过滤器
package com.example.gateway.filter;
import com.example.gateway.util.JwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
private final AntPathMatcher pathMatcher = new AntPathMatcher();
// 白名单路径:不需要鉴权的接口
private static final List<String> WHITE_LIST = List.of(
"/api/user/login",
"/api/user/register",
"/api/public/**",
"/actuator/**"
);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
// 1. 白名单校验
if (isWhiteListed(path)) {
return chain.filter(exchange);
}
// 2. 获取 token
String token = request.getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
return unauthorized(exchange, "缺少认证令牌");
}
token = token.substring(7);
// 3. 校验 token
if (!JwtUtil.validateToken(token)) {
return unauthorized(exchange, "认证令牌无效或已过期");
}
// 4. 解析用户信息并传递给下游服务
Claims claims = JwtUtil.parseToken(token);
String userId = claims.getSubject();
String username = claims.get("username", String.class);
// 将用户信息写入请求头,下游服务可直接读取
ServerHttpRequest mutatedRequest = request.mutate()
.header("X-User-Id", userId)
.header("X-Username", username)
.build();
return chain.filter(exchange.mutate().request(mutatedRequest).build());
}
private boolean isWhiteListed(String path) {
return WHITE_LIST.stream()
.anyMatch(pattern -> pathMatcher.match(pattern, path));
}
private Mono<Void> unauthorized(ServerWebExchange exchange, String message) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
exchange.getResponse().getHeaders().add("Content-Type", "application/json;charset=UTF-8");
String body = "{\"code\":401,\"message\":\"" + message + "\"}";
var buffer = exchange.getResponse().bufferFactory().wrap(body.getBytes());
return exchange.getResponse().writeWith(Mono.just(buffer));
}
@Override
public int getOrder() {
return -100; // 最高优先级,先鉴权
}
}
设计要点: 鉴权通过后,将用户信息通过请求头传递给下游服务。下游服务直接从头中读取 X-User-Id,无需再次解析 JWT。
8. 统一日志过滤器
记录所有请求的访问日志,便于排查问题和性能分析。
package com.example.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.UUID;
@Component
public class AccessLogFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
long startTime = System.currentTimeMillis();
String requestId = UUID.randomUUID().toString().substring(0, 8);
// 请求信息
String method = exchange.getRequest().getMethod().name();
String path = exchange.getRequest().getURI().getPath();
String clientIp = exchange.getRequest().getRemoteAddress() != null
? exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
: "unknown";
// 添加请求 ID 到请求头
var mutatedRequest = exchange.getRequest().mutate()
.header("X-Request-Id", requestId)
.build();
return chain.filter(exchange.mutate().request(mutatedRequest).build())
.then(Mono.fromRunnable(() -> {
long duration = System.currentTimeMillis() - startTime;
int statusCode = exchange.getResponse().getStatusCode() != null
? exchange.getResponse().getStatusCode().value()
: 0;
System.out.printf("[GATEWAY] %s | %s | %s %s | %d | %dms%n",
requestId, clientIp, method, path, statusCode, duration);
}));
}
@Override
public int getOrder() {
return -200; // 在鉴权之前执行,记录所有请求
}
}
输出示例:
[GATEWAY] a3f1b2c4 | 192.168.1.100 | GET /api/user/profile | 200 | 45ms
[GATEWAY] d7e8f9a0 | 192.168.1.101 | POST /api/order/create | 201 | 128ms
9. 限流:基于 Redis 令牌桶
9.1 内置 RequestRateLimiter 过滤器
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 # 令牌填充速率:10 个/秒
redis-rate-limiter.burstCapacity: 20 # 令牌桶容量:20
redis-rate-limiter.requestedTokens: 1 # 每个请求消耗 1 个令牌
9.2 自定义 KeyResolver(按用户限流)
package com.example.gateway.config;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Configuration
public class RateLimiterConfig {
/**
* 按用户 ID 限流
*/
@Bean
public KeyResolver userKeyResolver() {
return exchange -> {
String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
return Mono.just(userId != null ? userId : "anonymous");
};
}
/**
* 按 IP 限流
*/
@Bean
public KeyResolver ipKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getRemoteAddress()
.getAddress().getHostAddress()
);
}
/**
* 按 API 路径限流
*/
@Bean
public KeyResolver apiKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getURI().getPath());
}
}
使用自定义 KeyResolver:
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@userKeyResolver}" # 引用 Bean 名称
10. 跨域处理(CORS)
10.1 全局 CORS 配置
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins:
allowedMethods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
allowedHeaders:
- "*"
allowCredentials: true
maxAge: 3600 # 预检请求缓存时间(秒)
10.2 路由级别 CORS
如果不同路由有不同的 CORS 策略:
spring:
cloud:
gateway:
routes:
- id: public-api
uri: lb://public-service
predicates:
- Path=/api/public/**
filters:
- name: DedupeResponseHeader # 去重 CORS 响应头
args:
name: Access-Control-Allow-Origin
strategy: RETAIN_FIRST
11. 熔断降级
11.1 引入依赖
<!-- Resilience4j 熔断器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
11.2 配置熔断过滤器
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**
filters:
- StripPrefix=1
- name: CircuitBreaker
args:
name: userCircuitBreaker
fallbackUri: forward:/fallback/user # 降级接口
statusCodes:
- 500
- 502
- 503
- "NOT_FOUND"
# Resilience4j 配置
resilience4j:
circuitbreaker:
configs:
default:
slidingWindowSize: 10 # 滑动窗口大小
minimumNumberOfCalls: 5 # 最小调用次数
failureRateThreshold: 50 # 失败率阈值(%)
waitDurationInOpenState: 10s # 熔断开启后等待时间
permittedNumberOfCallsInHalfOpenState: 3 # 半开状态允许的调用数
instances:
userCircuitBreaker:
baseConfig: default
timelimiter:
configs:
default:
timeoutDuration: 3s # 超时时间
11.3 降级处理器
package com.example.gateway.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.ResponseEntity;
import java.util.Map;
@RestController
public class FallbackController {
@GetMapping("/fallback/user")
public ResponseEntity<Map<String, Object>> userFallback() {
return ResponseEntity.ok(Map.of(
"code", 503,
"message", "用户服务暂时不可用,请稍后重试",
"data", Map.of()
));
}
@GetMapping("/fallback/order")
public ResponseEntity<Map<String, Object>> orderFallback() {
return ResponseEntity.ok(Map.of(
"code", 503,
"message", "订单服务暂时不可用,请稍后重试",
"data", Map.of()
));
}
}
12. 完整生产级配置
以下是整合了所有功能的完整配置文件:
server:
port: 8080
spring:
application:
name: gateway-service
data:
redis:
host: 127.0.0.1
port: 6379
timeout: 3000
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: dev
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
namespace: dev
gateway:
# HTTP 客户端调优
httpclient:
connect-timeout: 3000
response-timeout: 10s
pool:
max-connections: 500
acquire-timeout: 5000
type: ELASTIC
# 全局跨域
globalcors:
cors-configurations:
'[/**]':
allowedOrigins:
- "Example Domain"
allowedMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
allowedHeaders: ["*"]
allowCredentials: true
maxAge: 3600
# 默认过滤器(所有路由生效)
default-filters:
- AddRequestHeader=X-Gateway, gateway-service
- AddResponseHeader=X-Response-From, gateway
# 路由配置
routes:
# 用户服务
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**
filters:
- StripPrefix=1
- name: CircuitBreaker
args:
name: userCircuitBreaker
fallbackUri: forward:/fallback/user
statusCodes: [500, 502, 503]
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 20
redis-rate-limiter.burstCapacity: 40
key-resolver: "#{@userKeyResolver}"
# 订单服务
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/order/**
filters:
- StripPrefix=1
- name: CircuitBreaker
args:
name: orderCircuitBreaker
fallbackUri: forward:/fallback/order
statusCodes: [500, 502, 503]
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@ipKeyResolver}"
# 支付服务(高安全:仅 POST)
- id: payment-service
uri: lb://payment-service
predicates:
- Path=/api/payment/**
- Method=POST
filters:
- StripPrefix=1
- name: RequestSize
args:
maxSize: 1MB
# 文件服务(大请求体)
- id: file-service
uri: lb://file-service
predicates:
- Path=/api/file/**
filters:
- StripPrefix=1
- name: RequestSize
args:
maxSize: 50MB
# Resilience4j 熔断配置
resilience4j:
circuitbreaker:
configs:
default:
slidingWindowSize: 10
minimumNumberOfCalls: 5
failureRateThreshold: 50
waitDurationInOpenState: 10s
permittedNumberOfCallsInHalfOpenState: 3
instances:
userCircuitBreaker:
baseConfig: default
orderCircuitBreaker:
baseConfig: default
timelimiter:
configs:
default:
timeoutDuration: 5s
# 日志
logging:
level:
org.springframework.cloud.gateway: INFO
com.example.gateway: DEBUG
13. 常见问题与最佳实践
13.1 常见坑
|
问题 |
原因 |
解决方案 |
|---|---|---|
|
启动报错 Spring MVC found on classpath |
引入了 spring-boot-starter-web |
排除 web 依赖,Gateway 基于 WebFlux |
|
lb:// 路由 503 |
未引入 LoadBalancer 依赖 |
添加 spring-cloud-starter-loadbalancer |
|
跨域仍报错 |
下游服务也配置了 CORS |
只在网关配置 CORS,下游移除 |
|
过滤器不生效 |
@Order 值在系统保留范围外 |
使用 -10000 ~ 10000 范围内 |
|
POST 请求 body 丢失 |
过滤器中读取 body 后未重写 |
使用 ModifyRequestBody 过滤器 |
13.2 过滤器执行顺序建议
优先级从高到低: ───────────────────────────────── @Order(-200) AccessLogFilter ← 记录所有请求(含被拒绝的)
@Order(-100) AuthGlobalFilter ← JWT 鉴权
@Order(-50) RateLimitFilter ← 限流
@Order(0) [内置过滤器] ← Gateway 内置功能
@Order(100) ResponseFilter ← 统一响应处理 ─────────────────────────────────
13.3 生产环境最佳实践
-
统一入口:所有外部请求必须经过网关,内部服务间通信可直连
-
白名单最小化:只暴露登录、注册等真正不需要认证的接口
-
限流分层:网关层 IP 限流 + 服务层用户限流
-
熔断隔离:每个下游服务独立熔断配置,避免雪崩
-
配置外置:路由配置放 Nacos,支持热更新
-
健康检查:配置 actuator 健康检查端点,配合 K8s 就绪探针
-
监控告警:集成 Prometheus + Grafana,监控 QPS、延迟、错误率
# actuator 暴露网关端点
management:
endpoints:
web:
exposure:
include: gateway,health,info,prometheus
endpoint:
gateway:
enabled: true # /actuator/gateway/routes 查看路由列表
附录:快速验证清单
# 1. 查看所有路由
curl http://localhost:8080/actuator/gateway/routes
# 2. 查看指定路由
curl http://localhost:8080/actuator/gateway/routes/user-service
# 3. 测试路由转发
curl -H "Authorization: Bearer <your-token>" \
http://localhost:8080/api/user/profile
# 4. 测试限流(快速发送大量请求)
for i in $(seq 1 30); do
curl -s -o /dev/null -w "%{http_code}\n" \
http://localhost:8080/api/user/list
done
# 预期:部分请求返回 429
# 5. 测试熔断降级
curl http://localhost:8080/api/user/info
# 当用户服务不可用时,预期返回降级响应
启动网关后,可以通过以下方式验证:
# 1. 查看所有路由
curl http://localhost:8080/actuator/gateway/routes
# 2. 查看指定路由
curl http://localhost:8080/actuator/gateway/routes/user-service
# 3. 测试路由转发
curl -H "Authorization: Bearer <your-token>" \
http://localhost:8080/api/user/profile
# 4. 测试限流(快速发送大量请求)
for i in $(seq 1 30); do
curl -s -o /dev/null -w "%{http_code}\n" \
http://localhost:8080/api/user/list
done
# 预期:部分请求返回 429
# 5. 测试熔断降级
curl http://localhost:8080/api/user/info
# 当用户服务不可用时,预期返回降级响应
教程版本:基于 Spring Boot 3.2.x + Spring Cloud 2023.x + Spring Cloud Alibaba 2023.x 参考文档:Spring Cloud Gateway 官方文档 | Spring Cloud 中文文档
更多推荐



所有评论(0)