Spring Cloud 网关
1. API 网关概述
1.1 什么是 API 网关
API 网关是微服务架构的统一入口,负责请求路由、协议转换、认证授权、限流熔断等功能。
1.2 网关核心功能
| 功能 | 说明 |
|---|---|
| 路由转发 | 请求路由到后端服务 |
| 负载均衡 | 多实例负载均衡 |
| 认证授权 | 统一身份认证 |
| 限流熔断 | 保护后端服务 |
| 日志监控 | 请求日志记录 |
| 协议转换 | HTTP/gRPC 转换 |
2. Spring Cloud Gateway
2.1 添加依赖
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>2.2 基本路由配置
yaml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
- id: product-service
uri: lb://product-service
predicates:
- Path=/api/products/**2.3 路由谓词
yaml
spring:
cloud:
gateway:
routes:
- id: path-route
uri: lb://user-service
predicates:
- Path=/api/users/**
- id: method-route
uri: lb://user-service
predicates:
- Method=GET,POST
- id: header-route
uri: lb://user-service
predicates:
- Header=X-Request-Id, \d+
- id: query-route
uri: lb://user-service
predicates:
- Query=token
- id: time-route
uri: lb://user-service
predicates:
- After=2024-01-01T00:00:00+08:00[Asia/Shanghai]
- id: cookie-route
uri: lb://user-service
predicates:
- Cookie=session, .+
- id: host-route
uri: lb://user-service
predicates:
- Host=**.example.com
- id: remote-addr-route
uri: lb://user-service
predicates:
- RemoteAddr=192.168.1.1/242.4 组合谓词
yaml
spring:
cloud:
gateway:
routes:
- id: combined-route
uri: lb://user-service
predicates:
- Path=/api/users/**
- Method=GET
- Header=X-API-Version, v13. 过滤器
3.1 内置过滤器
yaml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- AddRequestHeader=X-Request-Foo, Bar
- AddRequestParameter=foo, bar
- AddResponseHeader=X-Response-Foo, Bar
- StripPrefix=1
- PrefixPath=/api
- RewritePath=/api/(?<segment>.*), /$\{segment}
- SetPath=/api/{segment}
- SetRequestHeader=X-Request-Id, ${value}
- SetResponseHeader=X-Response-Id, ${value}
- SetStatus=200
- RequestRateLimiter=10,20
- CircuitBreaker=myCircuitBreaker3.2 自定义过滤器
java
@Component
public class AuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || !validateToken(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -100;
}
private boolean validateToken(String token) {
return token.startsWith("Bearer ");
}
}3.3 网关过滤器工厂
java
@Component
public class RequestTimeGatewayFilterFactory
extends AbstractGatewayFilterFactory<RequestTimeConfig> {
public RequestTimeGatewayFilterFactory() {
super(RequestTimeConfig.class);
}
@Override
public GatewayFilter apply(RequestTimeConfig config) {
return (exchange, chain) -> {
long startTime = System.currentTimeMillis();
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
long duration = System.currentTimeMillis() - startTime;
exchange.getResponse().getHeaders()
.add("X-Response-Time", duration + "ms");
}));
};
}
}
public class RequestTimeConfig {
private boolean showArgs;
// getter and setter
}4. 限流
4.1 基于 Redis 限流
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>yaml
spring:
redis:
host: localhost
port: 6379
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
redis-rate-limiter.requestedTokens: 1
key-resolver: "#{@userKeyResolver}"java
@Configuration
public class RateLimiterConfig {
@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 ipKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest()
.getRemoteAddress()
.getAddress()
.getHostAddress()
);
}
@Bean
public KeyResolver apiKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest()
.getPath()
.value()
);
}
}4.2 自定义限流
java
@Component
public class CustomRateLimiter implements RateLimiter {
private final Map<String, RateLimiter> limiters = new ConcurrentHashMap<>();
@Override
public Mono<Response> isAllowed(String routeId, String id) {
RateLimiter limiter = limiters.computeIfAbsent(id,
k -> RateLimiter.create(10.0));
boolean allowed = limiter.tryAcquire();
return Mono.just(new Response(allowed,
allowed ? 0 : 1));
}
}5. 熔断降级
5.1 添加依赖
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>5.2 配置熔断
yaml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- name: CircuitBreaker
args:
name: userServiceCircuitBreaker
fallbackUri: forward:/fallback/users
resilience4j:
circuitbreaker:
configs:
default:
slidingWindowSize: 10
failureRateThreshold: 50
waitDurationInOpenState: 10s
permittedNumberOfCallsInHalfOpenState: 5
instances:
userServiceCircuitBreaker:
baseConfig: default5.3 降级处理
java
@RestController
public class FallbackController {
@GetMapping("/fallback/users")
public Mono<Map<String, Object>> userFallback() {
return Mono.just(Map.of(
"code", 503,
"message", "用户服务暂时不可用",
"data", Collections.emptyList()
));
}
@GetMapping("/fallback/orders")
public Mono<Map<String, Object>> orderFallback() {
return Mono.just(Map.of(
"code", 503,
"message", "订单服务暂时不可用",
"data", Collections.emptyList()
));
}
}6. 认证授权
6.1 JWT 认证过滤器
java
@Component
public class JwtAuthFilter implements GlobalFilter, Ordered {
private final JwtTokenProvider tokenProvider;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String path = exchange.getRequest().getPath().value();
if (isPublicPath(path)) {
return chain.filter(exchange);
}
String token = extractToken(exchange);
if (token == null || !tokenProvider.validateToken(token)) {
return unauthorized(exchange);
}
String userId = tokenProvider.getUserIdFromToken(token);
ServerHttpRequest request = exchange.getRequest().mutate()
.header("X-User-Id", userId)
.build();
return chain.filter(exchange.mutate().request(request).build());
}
private boolean isPublicPath(String path) {
return path.startsWith("/api/auth/") ||
path.startsWith("/api/public/");
}
private String extractToken(ServerWebExchange exchange) {
String bearer = exchange.getRequest()
.getHeaders()
.getFirst("Authorization");
if (bearer != null && bearer.startsWith("Bearer ")) {
return bearer.substring(7);
}
return null;
}
private Mono<Void> unauthorized(ServerWebExchange exchange) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
exchange.getResponse().getHeaders()
.setContentType(MediaType.APPLICATION_JSON);
String body = "{\"code\":401,\"message\":\"Unauthorized\"}";
DataBuffer buffer = exchange.getResponse()
.bufferFactory()
.wrap(body.getBytes());
return exchange.getResponse().writeWith(Mono.just(buffer));
}
@Override
public int getOrder() {
return -100;
}
}7. 跨域配置
7.1 全局跨域
yaml
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOriginPatterns: "*"
allowedMethods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
allowedHeaders: "*"
allowCredentials: true
maxAge: 36007.2 代码配置
java
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOriginPatterns(List.of("*"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
config.setAllowedHeaders(List.of("*"));
config.setAllowCredentials(true);
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}8. 日志记录
8.1 请求日志过滤器
java
@Component
public class RequestLogFilter implements GlobalFilter, Ordered {
private static final Logger log = LoggerFactory.getLogger(RequestLogFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
long startTime = System.currentTimeMillis();
String requestId = UUID.randomUUID().toString();
log.info("Request: {} {} - {}",
request.getMethod(),
request.getPath(),
requestId);
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
long duration = System.currentTimeMillis() - startTime;
int statusCode = exchange.getResponse().getStatusCode().value();
log.info("Response: {} - {} ms - {}",
statusCode,
duration,
requestId);
}));
}
@Override
public int getOrder() {
return -200;
}
}9. 动态路由
9.1 动态路由配置
java
@Service
public class DynamicRouteService {
private final RouteDefinitionLocator routeDefinitionLocator;
private final RouteDefinitionWriter routeDefinitionWriter;
public void addRoute(RouteDefinition definition) {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
}
public void updateRoute(RouteDefinition definition) {
deleteRoute(definition.getId());
addRoute(definition);
}
public void deleteRoute(String routeId) {
routeDefinitionWriter.delete(Mono.just(routeId)).subscribe();
}
public Flux<RouteDefinition> getRoutes() {
return routeDefinitionLocator.getRouteDefinitions();
}
}
@RestController
@RequestMapping("/routes")
public class RouteController {
private final DynamicRouteService routeService;
@PostMapping
public String addRoute(@RequestBody RouteDefinition definition) {
routeService.addRoute(definition);
return "success";
}
@DeleteMapping("/{id}")
public String deleteRoute(@PathVariable String id) {
routeService.deleteRoute(id);
return "success";
}
}10. 小结
本章学习了 Spring Cloud Gateway 的核心内容:
| 内容 | 要点 |
|---|---|
| 路由配置 | 谓词、URI、优先级 |
| 过滤器 | 内置过滤器、自定义过滤器 |
| 限流 | Redis 限流、自定义限流 |
| 熔断降级 | Resilience4j、降级处理 |
| 认证授权 | JWT 认证、权限校验 |
| 跨域配置 | 全局跨域、代码配置 |
| 日志记录 | 请求日志、响应日志 |
| 动态路由 | 动态添加、更新、删除 |
下一章将学习 Spring Cloud 服务调用。