Gateway 高级特性
Spring Cloud Gateway 高级特性
前置知识
在学习本教程之前,建议您已经掌握:
- Spring Cloud Gateway 的基本概念和使用方法
- Spring Boot 和 Spring Cloud 的基础知识
- 微服务架构的基本原理
动态路由配置
在实际的微服务架构中,服务实例可能会动态变化,因此网关需要能够动态地更新路由信息。Spring Cloud Gateway 提供了多种方式来实现动态路由配置。
基于服务发现的动态路由
与 Eureka 集成
首先,添加 Eureka Client 依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
然后,在配置文件中启用服务发现:
spring:
cloud:
gateway:
discovery:
locator:
enabled: true # 启用服务发现
lower-case-service-id: true # 将服务ID转换为小写
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
这样,Gateway 就会自动为注册到 Eureka 的服务创建路由,路由格式为:http://gateway-host:gateway-port/service-id/**
。
与 Consul 集成
添加 Consul 依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
配置文件:
spring:
cloud:
consul:
host: localhost
port: 8500
gateway:
discovery:
locator:
enabled: true
基于数据库的动态路由
在实际项目中,我们可能需要将路由信息存储在数据库中,以便于管理和动态更新。下面是一个基于数据库的动态路由实现示例:
基于数据库的动态路由实现
package com.example.gateway.route;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.List;
@Component
public class DatabaseRouteDefinitionRepository implements RouteDefinitionRepository {
@Autowired
private RouteRepository routeRepository;
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
List<RouteEntity> routes = routeRepository.findAll();
return Flux.fromIterable(routes)
.map(this::convertToRouteDefinition);
}
@Override
public Mono<Void> save(Mono<RouteDefinition> route) {
return route.flatMap(r -> {
RouteEntity entity = convertToRouteEntity(r);
routeRepository.save(entity);
return Mono.empty();
});
}
@Override
public Mono<Void> delete(Mono<String> routeId) {
return routeId.flatMap(id -> {
routeRepository.deleteById(id);
return Mono.empty();
});
}
private RouteDefinition convertToRouteDefinition(RouteEntity entity) {
// 实现从数据库实体到RouteDefinition的转换
// ...
}
private RouteEntity convertToRouteEntity(RouteDefinition definition) {
// 实现从RouteDefinition到数据库实体的转换
// ...
}
}
路由刷新机制
当路由信息发生变化时,我们需要刷新 Gateway 的路由配置。Spring Cloud Gateway 提供了 RefreshRoutesEvent
事件来实现这一功能:
@Autowired
private ApplicationEventPublisher publisher;
public void refreshRoutes() {
publisher.publishEvent(new RefreshRoutesEvent(this));
}
高级过滤器功能
请求和响应修改
修改请求体
使用 ModifyRequestBodyGatewayFilterFactory
可以修改请求体:
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("modify-request-body", r -> r.path("/modify/**")
.filters(f -> f.modifyRequestBody(
String.class,
String.class,
(exchange, s) -> Mono.just(s.toUpperCase())
))
.uri("http://localhost:8081"))
.build();
}
修改响应体
使用 ModifyResponseBodyGatewayFilterFactory
可以修改响应体:
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("modify-response-body", r -> r.path("/modify/**")
.filters(f -> f.modifyResponseBody(
String.class,
String.class,
(exchange, s) -> Mono.just(s.toUpperCase())
))
.uri("http://localhost:8081"))
.build();
}
重试机制
Spring Cloud Gateway 提供了重试过滤器,可以在请求失败时进行重试:
spring:
cloud:
gateway:
routes:
- id: retry-route
uri: http://localhost:8081
predicates:
- Path=/retry/**
filters:
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY
methods: GET,POST
backoff:
firstBackoff: 10ms
maxBackoff: 50ms
factor: 2
basedOnPreviousValue: false
熔断器集成
Spring Cloud Gateway 可以与 Resilience4j 或 Spring Cloud Circuit Breaker 集成,提供熔断功能:
添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
配置熔断器
spring:
cloud:
gateway:
routes:
- id: circuit-breaker-route
uri: http://localhost:8081
predicates:
- Path=/cb/**
filters:
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/fallback
实现降级服务
@RestController
public class FallbackController {
@GetMapping("/fallback")
public Mono<String> fallback() {
return Mono.just("服务暂时不可用,请稍后再试");
}
}
限流与流量控制
基于 Redis 的限流器
Spring Cloud Gateway 提供了基于 Redis 的限流实现:
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
配置限流器
spring:
cloud:
gateway:
routes:
- id: rate-limit-route
uri: http://localhost:8081
predicates:
- Path=/rate-limit/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1 # 令牌桶每秒填充速率
redis-rate-limiter.burstCapacity: 2 # 令牌桶总容量
redis-rate-limiter.requestedTokens: 1 # 每个请求消耗的令牌数
key-resolver: "#{@userKeyResolver}" # 用于限流的键的解析器
自定义键解析器
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
自定义限流器
自定义限流过滤器工厂
package com.example.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class CustomRateLimiterGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomRateLimiterGatewayFilterFactory.Config> {
private final ConcurrentMap<String, AtomicInteger> counters = new ConcurrentHashMap<>();
public CustomRateLimiterGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
AtomicInteger counter = counters.computeIfAbsent(ip, k -> new AtomicInteger(0));
int current = counter.incrementAndGet();
if (current > config.getMaxRequests()) {
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange).then().doFinally(signalType -> {
counter.decrementAndGet();
});
};
}
public static class Config {
private int maxRequests = 10;
public int getMaxRequests() {
return maxRequests;
}
public void setMaxRequests(int maxRequests) {
this.maxRequests = maxRequests;
}
}
}
跨域配置
Spring Cloud Gateway 提供了全局和局部的跨域配置:
全局跨域配置
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
基于路由的跨域配置
spring:
cloud:
gateway:
routes:
- id: cors-route
uri: http://localhost:8081
predicates:
- Path=/api/**
filters:
- name: CORS
args:
allowedOrigins: "*"
allowedMethods: GET,POST,PUT,DELETE
allowedHeaders: "*"
WebSocket 支持
Spring Cloud Gateway 支持 WebSocket 协议,可以将 WebSocket 请求路由到后端服务:
spring:
cloud:
gateway:
routes:
- id: websocket-route
uri: ws://localhost:8081
predicates:
- Path=/ws/**
文件上传处理
Spring Cloud Gateway 可以处理文件上传请求,但需要注意内存使用:
spring:
cloud:
gateway:
routes:
- id: upload-route
uri: http://localhost:8081
predicates:
- Path=/upload/**
codec:
max-in-memory-size: 10MB # 设置最大内存缓冲区大小
安全性配置
与 Spring Security 集成
Spring Security 集成示例
package com.example.gateway.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.csrf().disable()
.authorizeExchange()
.pathMatchers("/public/**").permitAll()
.pathMatchers("/api/**").authenticated()
.anyExchange().authenticated()
.and()
.httpBasic()
.and()
.formLogin();
return http.build();
}
}
JWT 认证
JWT 认证过滤器示例
package com.example.gateway.filter;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.beans.factory.annotation.Value;
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.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class JwtAuthenticationFilter implements GlobalFilter, Ordered {
@Value("${jwt.secret}")
private String secret;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
// 跳过不需要验证的路径
if (request.getURI().getPath().startsWith("/public/")) {
return chain.filter(exchange);
}
// 获取token
String token = request.getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 验证token
token = token.substring(7);
try {
Claims claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
// 将用户信息传递给下游服务
ServerHttpRequest modifiedRequest = request.mutate()
.header("X-User-Id", claims.getSubject())
.build();
return chain.filter(exchange.mutate().request(modifiedRequest).build());
} catch (Exception e) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
}
@Override
public int getOrder() {
return -100; // 确保在其他过滤器之前执行
}
}
监控与指标
Actuator 端点
Spring Cloud Gateway 集成了 Spring Boot Actuator,提供了多个端点用于监控和管理:
management:
endpoints:
web:
exposure:
include: gateway,health,info,metrics
endpoint:
gateway:
enabled: true
可用的 Gateway 特定端点:
/actuator/gateway/routes
:查看所有路由/actuator/gateway/routes/{id}
:查看特定路由/actuator/gateway/globalfilters
:查看全局过滤器/actuator/gateway/routefilters
:查看路由过滤器工厂
与 Prometheus 集成
添加 Prometheus 依赖:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
配置 Prometheus 端点:
management:
endpoints:
web:
exposure:
include: prometheus
metrics:
export:
prometheus:
enabled: true
高级案例:灰度发布
灰度发布(金丝雀发布)是一种将新版本逐步推向部分用户的发布策略。Spring Cloud Gateway 可以通过自定义过滤器实现灰度发布功能:
灰度发布过滤器示例
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 java.util.Arrays;
import java.util.List;
import java.util.Random;
@Component
public class GrayReleaseGatewayFilterFactory extends AbstractGatewayFilterFactory<GrayReleaseGatewayFilterFactory.Config> {
private final Random random = new Random();
public GrayReleaseGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
// 根据配置的灰度比例决定是否路由到新版本
boolean isGray = random.nextDouble() < config.getGrayPercentage();
// 也可以根据特定条件判断,如用户ID、设备类型等
String userId = request.getHeaders().getFirst("X-User-Id");
if (userId != null && config.getGrayUserIds().contains(userId)) {
isGray = true;
}
// 修改请求,添加灰度标记
ServerHttpRequest modifiedRequest = request.mutate()
.header("X-Gray-Release", String.valueOf(isGray))
.build();
return chain.filter(exchange.mutate().request(modifiedRequest).build());
};
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("grayPercentage", "grayUserIds");
}
public static class Config {
private double grayPercentage = 0.1; // 默认10%的流量导向新版本
private List<String> grayUserIds = Arrays.asList(); // 指定的用户ID列表
public double getGrayPercentage() {
return grayPercentage;
}
public void setGrayPercentage(double grayPercentage) {
this.grayPercentage = grayPercentage;
}
public List<String> getGrayUserIds() {
return grayUserIds;
}
public void setGrayUserIds(List<String> grayUserIds) {
this.grayUserIds = grayUserIds;
}
}
}
配置灰度发布路由:
spring:
cloud:
gateway:
routes:
- id: service-v1
uri: http://service-v1:8080
predicates:
- Path=/api/**
filters:
- GrayRelease=0.2,user1,user2
- RewritePath=/api/(?<segment>.*), /$\{segment}
- AddRequestHeader=X-Service-Version, v1
- id: service-v2
uri: http://service-v2:8080
predicates:
- Path=/api/**
- Header=X-Gray-Release, true
filters:
- RewritePath=/api/(?<segment>.*), /$\{segment}
- AddRequestHeader=X-Service-Version, v2
总结
本文介绍了 Spring Cloud Gateway 的多种高级特性,包括动态路由配置、高级过滤器功能、限流与流量控制、跨域配置、WebSocket 支持、文件上传处理、安全性配置、监控与指标,以及灰度发布等实际应用场景。
通过这些高级特性,Spring Cloud Gateway 可以满足微服务架构中各种复杂的网关需求,提供高性能、高可用的 API 网关服务。
下一步学习
- 学习 Spring Cloud Gateway 的最佳实践
- 了解如何在生产环境中部署和运维 Gateway
- 探索 Gateway 与其他微服务组件的集成方案
希望这个教程对您有所帮助!如果您有任何问题,欢迎在评论区讨论。