SpringCloud Gateway入门教程 - 微服务网关完整指南
SpringCloud Gateway入门教程 - 微服务网关完整指南
目录
- Spring Cloud Gateway简介
- 环境搭建
- 快速开始
- 核心概念
- 路由配置
- 断言(Predicate)详解
- 过滤器(Filter)详解
- 全局过滤器
- 限流配置
- 熔断降级
- 与注册中心集成
- 跨域配置
- 监控和日志
- 实际应用案例
- 最佳实践
- 常见问题
- 总结与进阶
1. Spring Cloud Gateway简介
API网关是微服务架构中的统一入口,所有外部请求都先经过网关,由网关进行路由转发、权限验证、限流、监控等处理。
API网关的作用:
- ✅ 统一入口:为所有微服务提供统一的访问入口
- ✅ 路由转发:根据规则将请求转发到对应的微服务
- ✅ 权限验证:统一处理认证和授权
- ✅ 限流熔断:保护后端服务,防止过载
- ✅ 监控日志:统一收集请求日志和监控数据
- ✅ 协议转换:支持HTTP、WebSocket等协议转换
Spring Cloud Gateway是Spring官方推出的第二代网关框架,基于Spring 5.0、Spring Boot 2.0和Project Reactor等技术开发,旨在为微服务架构提供简单、有效、统一的API路由管理方式。
核心特性:
- ✅ 基于WebFlux:非阻塞式响应式编程模型,性能优异
- ✅ 功能强大:支持路由、断言、过滤器等多种功能
- ✅ 易于扩展:支持自定义过滤器、断言等
- ✅ 集成方便:与Spring Cloud生态完美集成
- ✅ 限流支持:内置限流功能,支持Redis等
| 特性 | Spring Cloud Gateway | Zuul |
|---|---|---|
| 技术栈 | WebFlux(响应式) | Servlet(阻塞式) |
| 性能 | 高(非阻塞) | 中等(阻塞) |
| 功能 | 丰富 | 基础 |
| 维护 | 官方维护 | 已停止更新 |
| 学习曲线 | 中等 | 简单 |
结论: Spring Cloud Gateway是官方推荐的新一代网关,建议新项目使用Gateway。
三个核心概念:
- Route(路由):路由是网关的基本构建块,由ID、目标URI、断言集合和过滤器集合组成
- Predicate(断言):匹配HTTP请求的条件,用于判断请求是否符合路由规则
- Filter(过滤器):在请求被路由前后对请求和响应进行修改
工作流程:
客户端请求 → Gateway → Predicate匹配 → Filter处理 → 转发到后端服务2. 环境搭建
- JDK 8或更高版本(推荐JDK 11+)
- Maven 3.6+ 或 Gradle
- Spring Boot 2.4+(推荐2.7+)
- Spring Cloud 2020.0.0+(推荐2021.0.0+)
方式一:使用Spring Initializr
- 访问 https://start.spring.io/
- 选择项目信息:
- Project: Maven
- Language: Java
- Spring Boot: 2.7.x
- Dependencies: Spring Cloud Gateway
- 点击Generate下载项目
方式二:手动创建
创建标准的Spring Boot项目结构:
gateway-demo/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── gateway/
│ │ │ ├── GatewayApplication.java
│ │ │ ├── config/
│ │ │ ├── filter/
│ │ │ └── handler/
│ │ └── resources/
│ │ └── application.yml
│ └── test/
└── pom.xmlpom.xml配置
<?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
http://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>2.7.14</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>gateway-demo</artifactId>
<version>1.0.0</version>
<name>Gateway Demo</name>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.8</spring-cloud.version>
</properties>
<dependencies>
<!-- Spring Cloud Gateway -->
<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>
<!-- 限流支持(Redis) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<!-- 监控支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Lombok(可选) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<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>2021.0.5.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>package com.example.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}注意: Gateway项目不能引入spring-boot-starter-web依赖,因为Gateway基于WebFlux,与WebMVC冲突。
3. 快速开始
application.yml配置
server:
port: 8080
spring:
application:
name: gateway-service
cloud:
gateway:
routes:
# 路由1:转发到百度
- id: baidu-route
uri: https://www.baidu.com
predicates:
- Path=/baidu/**
filters:
- StripPrefix=1 # 去掉前缀/baidu
# 路由2:转发到本地服务
- id: local-route
uri: http://localhost:8081
predicates:
- Path=/api/**测试路由
启动Gateway服务后,访问:
http://localhost:8080/baidu/→ 转发到百度http://localhost:8080/api/xxx→ 转发到http://localhost:8081/api/xxx
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 GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
// 路由1
.route("baidu-route", r -> r
.path("/baidu/**")
.uri("https://www.baidu.com"))
// 路由2
.route("local-route", r -> r
.path("/api/**")
.uri("http://localhost:8081"))
.build();
}
}4. 核心概念
路由是Gateway的基本构建块,包含以下信息:
- id:路由的唯一标识
- uri:目标服务地址
- predicates:断言集合,用于匹配请求
- filters:过滤器集合,用于处理请求和响应
断言用于匹配HTTP请求,只有满足断言条件的请求才会被路由。
常见断言类型:
- Path:路径匹配
- Method:HTTP方法匹配
- Header:请求头匹配
- Query:查询参数匹配
- Cookie:Cookie匹配
- Time:时间匹配
- RemoteAddr:IP地址匹配
过滤器用于在请求被路由前后对请求和响应进行修改。
过滤器类型:
- GatewayFilter:路由过滤器,只作用于特定路由
- GlobalFilter:全局过滤器,作用于所有路由
执行顺序:
请求 → Pre过滤器 → 路由转发 → Post过滤器 → 响应5. 路由配置
基本路由配置
spring:
cloud:
gateway:
routes:
- id: user-service
uri: http://localhost:8081
predicates:
- Path=/user/**
filters:
- StripPrefix=1多个路由配置
spring:
cloud:
gateway:
routes:
- id: user-service
uri: http://localhost:8081
predicates:
- Path=/user/**
- id: order-service
uri: http://localhost:8082
predicates:
- Path=/order/**
- id: product-service
uri: http://localhost:8083
predicates:
- Path=/product/**使用负载均衡
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service # lb表示负载均衡
predicates:
- Path=/user/**注意: 使用lb://需要集成服务注册中心(如Nacos、Eureka)。
@Configuration
public class RouteConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("user-service", r -> r
.path("/user/**")
.uri("http://localhost:8081"))
.route("order-service", r -> r
.path("/order/**")
.uri("http://localhost:8082"))
.build();
}
}Gateway支持从数据库、Redis等外部源动态加载路由配置。
@Configuration
public class DynamicRouteConfig {
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
@Autowired
private RouteDefinitionLocator routeDefinitionLocator;
/**
* 动态添加路由
*/
public void addRoute(RouteDefinition routeDefinition) {
routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
notifyChanged();
}
/**
* 动态删除路由
*/
public void deleteRoute(String routeId) {
routeDefinitionWriter.delete(Mono.just(routeId)).subscribe();
notifyChanged();
}
private void notifyChanged() {
// 通知路由更新
}
}6. 断言(Predicate)详解
根据请求路径匹配。
spring:
cloud:
gateway:
routes:
- id: path-route
uri: http://localhost:8081
predicates:
- Path=/api/user/**,/api/order/**代码方式:
.route("path-route", r -> r
.path("/api/user/**", "/api/order/**")
.uri("http://localhost:8081"))根据HTTP方法匹配。
predicates:
- Method=GET,POST代码方式:
.route("method-route", r -> r
.method(HttpMethod.GET, HttpMethod.POST)
.uri("http://localhost:8081"))根据请求头匹配。
predicates:
- Header=X-Request-Id, \d+ # 匹配X-Request-Id为数字的请求代码方式:
.route("header-route", r -> r
.header("X-Request-Id", "\\d+")
.uri("http://localhost:8081"))根据查询参数匹配。
predicates:
- Query=name,zhangsan # 必须包含name参数且值为zhangsan
- Query=age # 只需包含age参数,值任意代码方式:
.route("query-route", r -> r
.query("name", "zhangsan")
.uri("http://localhost:8081"))根据Cookie匹配。
predicates:
- Cookie=sessionId,abc123代码方式:
.route("cookie-route", r -> r
.cookie("sessionId", "abc123")
.uri("http://localhost:8081"))根据时间匹配。
predicates:
- After=2024-01-01T00:00:00+08:00 # 在此时间之后
- Before=2024-12-31T23:59:59+08:00 # 在此时间之前
- Between=2024-01-01T00:00:00+08:00,2024-12-31T23:59:59+08:00根据客户端IP匹配。
predicates:
- RemoteAddr=192.168.1.1/24 # IP段匹配多个断言可以组合使用,默认是AND关系。
predicates:
- Path=/api/**
- Method=GET
- Header=X-Request-Id, \d+
- Query=name7. 过滤器(Filter)详解
StripPrefix过滤器
去掉请求路径的前缀。
filters:
- StripPrefix=1 # 去掉1个前缀段示例:
- 请求:
/api/user/info - 转发:
/user/info
PrefixPath过滤器
添加路径前缀。
filters:
- PrefixPath=/api示例:
- 请求:
/user/info - 转发:
/api/user/info
AddRequestHeader过滤器
添加请求头。
filters:
- AddRequestHeader=X-Request-Id,12345AddRequestParameter过滤器
添加请求参数。
filters:
- AddRequestParameter=name,zhangsanAddResponseHeader过滤器
添加响应头。
filters:
- AddResponseHeader=X-Response-Time,100RemoveRequestHeader过滤器
移除请求头。
filters:
- RemoveRequestHeader=X-Secret-KeyRemoveResponseHeader过滤器
移除响应头。
filters:
- RemoveResponseHeader=X-Secret-KeySetRequestHeader过滤器
设置请求头(覆盖已存在的)。
filters:
- SetRequestHeader=X-Request-Id,new-valueSetResponseHeader过滤器
设置响应头。
filters:
- SetResponseHeader=X-Response-Time,200RewritePath过滤器
重写路径。
filters:
- RewritePath=/api/(?<segment>.*), /$\{segment} # /api/user -> /userRetry过滤器
重试机制。
filters:
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY,INTERNAL_SERVER_ERROR
methods: GET,POST
backoff:
firstBackoff: 50ms
maxBackoff: 500ms
factor: 2
basedOnPreviousValue: false创建自定义过滤器
package com.example.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
@Component
public class CustomGatewayFilterFactory
extends AbstractGatewayFilterFactory<CustomGatewayFilterFactory.Config> {
public CustomGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
// 前置处理
System.out.println("Custom filter pre: " + request.getURI());
// 添加请求头
ServerHttpRequest modifiedRequest = request.mutate()
.header("X-Custom-Header", config.getValue())
.build();
return chain.filter(exchange.mutate().request(modifiedRequest).build())
.then(Mono.fromRunnable(() -> {
// 后置处理
System.out.println("Custom filter post");
}));
};
}
public static class Config {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}使用自定义过滤器
filters:
- name: Custom
args:
value: custom-value8. 全局过滤器
全局过滤器作用于所有路由,不需要在路由配置中声明。
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.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String token = request.getHeaders().getFirst("Authorization");
// 验证token
if (token == null || !isValidToken(token)) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
// 添加用户信息到请求头
ServerHttpRequest modifiedRequest = request.mutate()
.header("X-User-Id", getUserIdFromToken(token))
.build();
return chain.filter(exchange.mutate().request(modifiedRequest).build());
}
@Override
public int getOrder() {
return 0; // 执行顺序,数字越小优先级越高
}
private boolean isValidToken(String token) {
// 实现token验证逻辑
return token != null && token.startsWith("Bearer ");
}
private String getUserIdFromToken(String token) {
// 从token中提取用户ID
return "user123";
}
}@Component
public class LoggingGlobalFilter implements GlobalFilter, Ordered {
private static final Logger log = LoggerFactory.getLogger(LoggingGlobalFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
String method = request.getMethod().name();
log.info("Request: {} {}", method, path);
long startTime = System.currentTimeMillis();
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
long endTime = System.currentTimeMillis();
log.info("Response: {} {} - {}ms", method, path, endTime - startTime);
}));
}
@Override
public int getOrder() {
return -1; // 优先级最高
}
}@Component
public class IpWhitelistFilter implements GlobalFilter, Ordered {
private final List<String> whitelist = Arrays.asList(
"127.0.0.1",
"192.168.1.0/24"
);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String clientIp = getClientIp(request);
if (!isAllowed(clientIp)) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.FORBIDDEN);
return response.setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
private String getClientIp(ServerHttpRequest request) {
String ip = request.getHeaders().getFirst("X-Forwarded-For");
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeaders().getFirst("X-Real-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddress() != null ?
request.getRemoteAddress().getAddress().getHostAddress() : "";
}
return ip;
}
private boolean isAllowed(String ip) {
// 实现IP白名单检查逻辑
return whitelist.contains(ip);
}
}9. 限流配置
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>配置Redis
spring:
redis:
host: localhost
port: 6379
password:
database: 0配置限流过滤器
spring:
cloud:
gateway:
routes:
- id: user-service
uri: http://localhost:8081
predicates:
- Path=/user/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 # 每秒允许的请求数
redis-rate-limiter.burstCapacity: 20 # 令牌桶容量
redis-rate-limiter.requestedTokens: 1 # 每次请求消耗的令牌数
key-resolver: "#{@ipKeyResolver}" # 限流key的解析器创建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 {
/**
* 根据IP限流
*/
@Bean
public KeyResolver ipKeyResolver() {
return exchange -> {
String ip = exchange.getRequest().getRemoteAddress() != null ?
exchange.getRequest().getRemoteAddress().getAddress().getHostAddress() : "";
return Mono.just(ip);
};
}
/**
* 根据用户ID限流
*/
@Bean
public KeyResolver userKeyResolver() {
return exchange -> {
String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
return Mono.just(userId != null ? userId : "anonymous");
};
}
/**
* 根据请求路径限流
*/
@Bean
public KeyResolver pathKeyResolver() {
return exchange -> {
String path = exchange.getRequest().getURI().getPath();
return Mono.just(path);
};
}
}@Component
public class CustomRateLimiterFilter implements GlobalFilter, Ordered {
private final RedisTemplate<String, String> redisTemplate;
private final int limit = 10; // 每秒10个请求
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String key = getKey(exchange);
String count = redisTemplate.opsForValue().get(key);
if (count == null) {
redisTemplate.opsForValue().set(key, "1", Duration.ofSeconds(1));
return chain.filter(exchange);
}
int currentCount = Integer.parseInt(count);
if (currentCount >= limit) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return response.setComplete();
}
redisTemplate.opsForValue().increment(key);
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -100;
}
private String getKey(ServerWebExchange exchange) {
String ip = exchange.getRequest().getRemoteAddress() != null ?
exchange.getRequest().getRemoteAddress().getAddress().getHostAddress() : "";
return "rate_limit:" + ip;
}
}10. 熔断降级
添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>配置熔断
spring:
cloud:
gateway:
routes:
- id: user-service
uri: http://localhost:8081
predicates:
- Path=/user/**
filters:
- name: CircuitBreaker
args:
name: userServiceCircuitBreaker
fallbackUri: forward:/fallback/user创建降级处理
@RestController
public class FallbackController {
@GetMapping("/fallback/user")
public ResponseEntity<Map<String, Object>> userFallback() {
Map<String, Object> result = new HashMap<>();
result.put("code", 500);
result.put("message", "用户服务暂时不可用,请稍后重试");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
}
}resilience4j:
circuitbreaker:
configs:
default:
slidingWindowSize: 10
minimumNumberOfCalls: 5
permittedNumberOfCallsInHalfOpenState: 3
automaticTransitionFromOpenToHalfOpenEnabled: true
waitDurationInOpenState: 5s
failureRateThreshold: 50
eventConsumerBufferSize: 10
instances:
userServiceCircuitBreaker:
baseConfig: default11. 与注册中心集成
添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>配置Nacos
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: public
group: DEFAULT_GROUP
gateway:
discovery:
locator:
enabled: true # 启用服务发现
lower-case-service-id: true # 服务名小写使用服务名路由
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service # lb表示负载均衡
predicates:
- Path=/user/**添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>配置Eureka
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/12. 跨域配置
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOriginPattern("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "*"
allowedMethods:
- GET
- POST
- PUT
- DELETE
allowedHeaders: "*"
allowCredentials: true13. 监控和日志
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
gateway:
enabled: true访问监控端点:
http://localhost:8080/actuator/gateway/routes- 查看所有路由http://localhost:8080/actuator/gateway/routefilters- 查看所有过滤器
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>14. 实际应用案例
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
discovery:
locator:
enabled: true
routes:
# 用户服务
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@ipKeyResolver}"
# 订单服务
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/order/**
filters:
- StripPrefix=1
- name: CircuitBreaker
args:
name: orderServiceCircuitBreaker
fallbackUri: forward:/fallback/order@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
// 白名单路径
if (isWhitelist(path)) {
return chain.filter(exchange);
}
// 获取token
String token = request.getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
return unauthorized(exchange);
}
token = token.substring(7);
// 验证token
String userId = redisTemplate.opsForValue().get("token:" + token);
if (userId == null) {
return unauthorized(exchange);
}
// 添加用户信息到请求头
ServerHttpRequest modifiedRequest = request.mutate()
.header("X-User-Id", userId)
.build();
return chain.filter(exchange.mutate().request(modifiedRequest).build());
}
private boolean isWhitelist(String path) {
return path.startsWith("/api/public/") ||
path.equals("/api/login") ||
path.equals("/api/register");
}
private Mono<Void> unauthorized(ServerWebExchange exchange) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
DataBuffer buffer = response.bufferFactory().wrap(
"{\"code\":401,\"message\":\"未授权\"}".getBytes(StandardCharsets.UTF_8));
return response.writeWith(Mono.just(buffer));
}
@Override
public int getOrder() {
return 0;
}
}15. 最佳实践
使用服务发现:优先使用
lb://服务名路由统一前缀:为所有路由添加统一前缀
合理分组:按业务模块分组路由
版本控制:使用路径版本控制API版本
连接池配置:合理配置HTTP连接池
缓存配置:启用路由缓存
限流配置:合理设置限流参数
过滤器顺序:优化过滤器执行顺序
认证授权:统一在网关处理认证授权
IP白名单:限制访问IP
HTTPS:生产环境使用HTTPS
敏感信息:不要在日志中输出敏感信息
16. 常见问题
Q1: Gateway启动失败,提示WebMVC冲突?
A: Gateway基于WebFlux,不能引入spring-boot-starter-web依赖。
Q2: 如何实现动态路由?
A: 可以通过监听配置中心变化或调用Gateway API动态更新路由。
Q3: 如何实现灰度发布?
A: 可以使用自定义过滤器,根据请求头或参数选择不同版本的服务。
Q4: Gateway性能如何?
A: Gateway基于WebFlux非阻塞模型,性能优异,可以处理大量并发请求。
17. 总结与进阶
通过本教程,你已经掌握了:
- ✅ Gateway的基本概念和配置
- ✅ 路由、断言、过滤器的使用
- ✅ 限流、熔断等高级特性
- ✅ 与注册中心的集成
- ✅ 实际应用场景
- 源码学习:深入理解Gateway的实现原理
- 性能优化:学习Gateway性能调优
- 扩展开发:开发自定义过滤器和断言
- 监控运维:集成监控和日志系统
- 官方文档:https://spring.io/projects/spring-cloud-gateway
- GitHub:https://github.com/spring-cloud/spring-cloud-gateway
- 示例项目:Spring Cloud官方示例
结语
Spring Cloud Gateway是微服务架构中不可或缺的组件,通过本教程的学习,相信你已经掌握了Gateway的核心功能和使用方法。
记住:
- 多实践:通过实际项目加深理解
- 关注性能:注意性能优化和监控
- 安全第一:重视安全配置
- 持续学习:关注Gateway的新特性
祝你学习愉快,编程顺利! 🚀
本教程由Java突击队学习社区编写,如有问题欢迎反馈。