本教程从零开始,带你完整掌握 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:

- "http://localhost:3000"

- "http://localhost:5173"

- "https://www.example.com"

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:

- "http://localhost:3000"

- "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 生产环境最佳实践

  1. 统一入口:所有外部请求必须经过网关,内部服务间通信可直连

  2. 白名单最小化:只暴露登录、注册等真正不需要认证的接口

  3. 限流分层:网关层 IP 限流 + 服务层用户限流

  4. 熔断隔离:每个下游服务独立熔断配置,避免雪崩

  5. 配置外置:路由配置放 Nacos,支持热更新

  6. 健康检查:配置 actuator 健康检查端点,配合 K8s 就绪探针

  7. 监控告警:集成 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 中文文档

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐