当前位置: 首页 > article >正文

SpringCloud网关:Gateway路由配置与过滤器链

在这里插入图片描述

文章目录

    • 引言
    • 一、Gateway基本架构
    • 二、路由配置方式
      • 2.1 配置文件方式
      • 2.2 Java代码方式
    • 三、内置断言工厂
    • 四、内置过滤器工厂
      • 4.1 请求路径相关过滤器
      • 4.2 请求和响应头过滤器
      • 4.3 功能性过滤器
    • 五、自定义过滤器
      • 5.1 自定义GatewayFilter
      • 5.2 自定义过滤器工厂
    • 六、全局过滤器
    • 总结

引言

在微服务架构中,API网关是整个系统的入口,负责请求路由、负载均衡、认证鉴权、限流熔断等关键功能。Spring Cloud Gateway作为Spring Cloud生态中的新一代API网关,基于Spring WebFlux和Reactor构建,提供了非阻塞、响应式的API网关解决方案。相比于Zuul,Gateway具有更强的性能和更丰富的功能。本文将深入探讨Spring Cloud Gateway的核心概念、路由配置方法以及过滤器链机制,帮助开发者构建高效的微服务网关。

一、Gateway基本架构

Spring Cloud Gateway的核心架构包括路由(Route)、断言(Predicate)和过滤器(Filter)三大组件。路由是网关的基本单元,包含目标URI、断言集合和过滤器集合。断言用于判断请求是否满足某种条件,满足条件的请求会被路由到指定服务。过滤器则用于对请求和响应进行修改,实现各种横切功能。

/**
 * Gateway的基本工作流程:
 * 1. 客户端发送请求到Gateway
 * 2. Gateway的HandlerMapping组件找到与请求匹配的路由
 * 3. 请求经过一系列过滤器的处理
 * 4. 到达目标服务并获取响应
 * 5. 响应再次经过过滤器的处理
 * 6. 最终返回给客户端
 */
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

Gateway的核心依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

二、路由配置方式

Spring Cloud Gateway提供了两种路由配置方式:配置文件方式和Java代码方式。开发者可以根据实际需求选择适合的配置方式。

2.1 配置文件方式

通过application.yml文件可以方便地配置路由规则,这种方式简单直观,适合大多数场景:

spring:
  cloud:
    gateway:
      routes:
        - id: user-service-route            # 路由ID,需保持唯一
          uri: lb://user-service            # 目标URI,lb表示使用负载均衡
          predicates:                        # 断言条件,满足条件的请求会被路由
            - Path=/api/users/**            # 路径匹配断言
            - Method=GET,POST               # HTTP方法匹配断言
            - Header=X-Request-Id, \d+      # 请求头匹配断言
          filters:                          # 过滤器
            - StripPrefix=1                 # 去除路径前缀
            - AddRequestHeader=X-Gateway-Timestamp, ${now}  # 添加请求头
            
        - id: order-service-route
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
            - Between=2022-01-01T00:00:00+08:00[Asia/Shanghai],2023-12-31T23:59:59+08:00[Asia/Shanghai]  # 时间范围断言
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter      # 限流过滤器
              args:
                redis-rate-limiter.replenishRate: 10  # 令牌桶填充速率
                redis-rate-limiter.burstCapacity: 20   # 令牌桶容量
                key-resolver: "#{@userKeyResolver}"    # 限流键解析器

2.2 Java代码方式

使用Java代码配置路由提供了更灵活的编程能力,可以根据条件动态生成路由规则:

/**
 * 使用Java代码配置路由
 */
@Configuration
public class RouteConfig {
    
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            // 用户服务路由
            .route("user-service-route", r -> r
                .path("/api/users/**")
                .and().method("GET", "POST")
                .filters(f -> f
                    .stripPrefix(1)
                    .addRequestHeader("X-Gateway-Timestamp", 
                                     String.valueOf(System.currentTimeMillis()))
                    .requestRateLimiter(c -> c
                        .setRateLimiter(redisRateLimiter())
                        .setKeyResolver(userKeyResolver()))
                )
                .uri("lb://user-service"))
            
            // 订单服务路由
            .route("order-service-route", r -> r
                .path("/api/orders/**")
                .filters(f -> f
                    .stripPrefix(1)
                    .retry(retryConfig -> retryConfig
                        .setRetries(3)
                        .setStatuses(HttpStatus.INTERNAL_SERVER_ERROR))
                )
                .uri("lb://order-service"))
            
            // 重定向路由
            .route("redirect-route", r -> r
                .path("/redirect/**")
                .filters(f -> f.redirect(302, "https://www.example.com"))
                .uri("no://op"))
            
            .build();
    }
    
    /**
     * Redis限流器
     */
    @Bean
    public RedisRateLimiter redisRateLimiter() {
        return new RedisRateLimiter(10, 20);
    }
    
    /**
     * 限流键解析器,基于用户ID
     */
    @Bean
    public KeyResolver userKeyResolver() {
        return exchange -> {
            String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
            if (userId == null) {
                userId = "anonymous";
            }
            return Mono.just(userId);
        };
    }
}

三、内置断言工厂

Spring Cloud Gateway提供了多种内置断言工厂,用于根据不同条件匹配路由。了解这些断言工厂的用法可以帮助开发者实现精细的路由控制。

常用的断言工厂包括:

  1. Path断言工厂:根据请求路径匹配路由
  2. Method断言工厂:根据HTTP方法匹配路由
  3. Header断言工厂:根据请求头匹配路由
  4. Query断言工厂:根据查询参数匹配路由
  5. Cookie断言工厂:根据Cookie匹配路由
  6. Host断言工厂:根据主机名匹配路由
  7. Between断言工厂:根据时间范围匹配路由
  8. Weight断言工厂:按比例将请求路由到不同服务
# 断言工厂使用示例
spring:
  cloud:
    gateway:
      routes:
        - id: complex-route
          uri: lb://example-service
          predicates:
            - Path=/api/{segment}/{id}      # 路径变量
            - Method=GET
            - Query=version, v[1-3]         # 查询参数正则匹配
            - Header=X-API-Version, \d+     # 请求头正则匹配
            - Cookie=session, \w+           # Cookie正则匹配
            - Host=**.example.org           # 主机名通配符匹配
            - Weight=group1, 8              # 按8:2的比例路由

四、内置过滤器工厂

Gateway的过滤器是实现网关功能的核心组件,可以对请求和响应进行各种处理。Gateway提供了丰富的内置过滤器工厂,满足常见的网关功能需求。

4.1 请求路径相关过滤器

filters:
  # 去除前缀
  - StripPrefix=1
  # 添加前缀
  - PrefixPath=/api
  # 路径重写
  - RewritePath=/api/(?<segment>.*), /$\{segment}
  # 设置路径变量
  - SetPath=/v2/{segment}

4.2 请求和响应头过滤器

filters:
  # 添加请求头
  - AddRequestHeader=X-Request-Id, ${requestId}
  # 添加响应头
  - AddResponseHeader=X-Response-Time, ${responseTime}
  # 移除请求头
  - RemoveRequestHeader=X-Unwanted-Header
  # 移除响应头
  - RemoveResponseHeader=X-Internal-Header
  # 修改请求头
  - MapRequestHeader=X-Old-Header, X-New-Header

4.3 功能性过滤器

filters:
  # 重定向
  - RedirectTo=302, https://example.org
  # 请求大小限制
  - RequestSize=5MB
  # 重试
  - name: Retry
    args:
      retries: 3
      statuses: INTERNAL_SERVER_ERROR
      methods: GET,POST
  # 熔断
  - name: CircuitBreaker
    args:
      name: defaultCircuitBreaker
      fallbackUri: forward:/fallback
  # 限流
  - name: RequestRateLimiter
    args:
      redis-rate-limiter.replenishRate: 10
      redis-rate-limiter.burstCapacity: 20
      key-resolver: "#{@userKeyResolver}"

五、自定义过滤器

除了使用内置过滤器外,Gateway还支持自定义过滤器,以满足特定业务需求。自定义过滤器有两种方式:实现GatewayFilter接口或继承AbstractGatewayFilterFactory类。

5.1 自定义GatewayFilter

/**
 * 自定义GatewayFilter
 * 记录请求处理时间
 */
@Component
public class RequestTimeFilter implements GatewayFilter, Ordered {
    
    private static final Logger log = LoggerFactory.getLogger(RequestTimeFilter.class);
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        exchange.getAttributes().put("requestTimeBegin", System.currentTimeMillis());
        
        return chain.filter(exchange).then(
            Mono.fromRunnable(() -> {
                Long startTime = exchange.getAttribute("requestTimeBegin");
                if (startTime != null) {
                    Long endTime = System.currentTimeMillis();
                    log.info("Request {} processed in {} ms", 
                             exchange.getRequest().getURI().getPath(), 
                             endTime - startTime);
                }
            })
        );
    }
    
    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}

/**
 * 在路由配置中使用自定义过滤器
 */
@Configuration
public class CustomFilterConfig {
    
    @Bean
    public RouteLocator customFilterRoute(RouteLocatorBuilder builder, RequestTimeFilter timeFilter) {
        return builder.routes()
            .route("custom-filter-route", r -> r
                .path("/api/custom/**")
                .filters(f -> f.filter(timeFilter))
                .uri("lb://custom-service"))
            .build();
    }
}

5.2 自定义过滤器工厂

/**
 * 自定义过滤器工厂
 * 添加请求日志
 */
@Component
public class RequestLogGatewayFilterFactory extends AbstractGatewayFilterFactory<RequestLogGatewayFilterFactory.Config> {
    
    private static final Logger log = LoggerFactory.getLogger(RequestLogGatewayFilterFactory.class);
    
    public RequestLogGatewayFilterFactory() {
        super(Config.class);
    }
    
    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            
            // 记录请求信息
            if (config.isLogHeaders()) {
                log.info("Request headers: {}", request.getHeaders());
            }
            
            log.info("Request method: {}, path: {}, client: {}", 
                     request.getMethod(), 
                     request.getURI().getPath(),
                     request.getRemoteAddress());
            
            return chain.filter(exchange);
        };
    }
    
    /**
     * 过滤器配置类
     */
    public static class Config {
        private boolean logHeaders;
        
        public boolean isLogHeaders() {
            return logHeaders;
        }
        
        public void setLogHeaders(boolean logHeaders) {
            this.logHeaders = logHeaders;
        }
    }
    
    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("logHeaders");
    }
}

在配置文件中使用自定义过滤器工厂:

spring:
  cloud:
    gateway:
      routes:
        - id: custom-filter-factory-route
          uri: lb://example-service
          predicates:
            - Path=/api/example/**
          filters:
            - RequestLog=true  # 使用自定义过滤器工厂,参数为logHeaders

六、全局过滤器

全局过滤器会应用到所有路由上,适合实现通用功能,如认证、监控、日志等。实现GlobalFilter接口可以创建全局过滤器。

/**
 * 全局认证过滤器
 * 对所有请求进行JWT认证
 */
@Component
public class AuthenticationFilter implements GlobalFilter, Ordered {
    
    @Autowired
    private JwtTokenValidator tokenValidator;
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        
        // 跳过公开API
        if (isPublicApi(request.getURI().getPath())) {
            return chain.filter(exchange);
        }
        
        // 获取token
        String token = getTokenFromRequest(request);
        if (token == null) {
            return unauthorized(exchange);
        }
        
        // 验证token
        if (!tokenValidator.validate(token)) {
            return unauthorized(exchange);
        }
        
        // 解析用户信息并放入请求头
        String userId = tokenValidator.getUserId(token);
        ServerHttpRequest mutatedRequest = request.mutate()
            .header("X-User-Id", userId)
            .build();
        
        return chain.filter(exchange.mutate().request(mutatedRequest).build());
    }
    
    private boolean isPublicApi(String path) {
        return path.startsWith("/api/public/") || path.startsWith("/auth/");
    }
    
    private String getTokenFromRequest(ServerHttpRequest request) {
        List<String> authHeaders = request.getHeaders().get("Authorization");
        if (authHeaders != null && !authHeaders.isEmpty()) {
            String authHeader = authHeaders.get(0);
            if (authHeader.startsWith("Bearer ")) {
                return authHeader.substring(7);
            }
        }
        return null;
    }
    
    private Mono<Void> unauthorized(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        
        return response.setComplete();
    }
    
    @Override
    public int getOrder() {
        return -100;  // 确保认证过滤器先执行
    }
}

总结

Spring Cloud Gateway作为新一代API网关,凭借其基于WebFlux的响应式特性,提供了高性能的请求路由和处理能力。本文介绍了Gateway的基本架构、路由配置方法、断言工厂使用、过滤器链机制以及自定义过滤器的实现方式。通过合理配置路由和过滤器,可以实现请求转发、负载均衡、认证鉴权、限流熔断等微服务网关的核心功能。

在实际应用中,开发者可以根据具体需求选择配置文件或Java代码方式定义路由,组合使用内置断言和过滤器,或实现自定义过滤器和全局过滤器,构建功能完备的API网关。随着微服务架构的不断发展,Gateway的非阻塞特性和丰富的功能使其成为构建现代微服务网关的理想选择。


http://www.kler.cn/a/592607.html

相关文章:

  • gitee AI使用
  • 人工智能混合编程实践:C++调用Python AgentOCR进行文本识别
  • Rust嵌入式开发之:Probe-rs工具安装
  • MySQL进阶篇-InnoDB引擎(逻辑存储结构、内存结构、磁盘结构、后台线程、事务原理、MVCC)
  • 使用springboot与vue开发头像功能
  • 优化器/模型参数/超参数
  • 【Java篇】一气化三清:类的实例化与封装的智慧之道
  • 【深度学习】走向VQ-VAE模型
  • 【Python】使用ImageEnhance提升图片画质
  • windows 10 系统配置Node
  • 使用htool工具导出和导入Excel表
  • AI 原生 IDE Trae 深度体验:SSHremote 功能如何重新定义远程开发与云原生部署
  • 基于Python+Django的旅游管理系统
  • 13-动态规划-最长公共子序列
  • CVPR2025 | TAPT:用于视觉语言模型鲁棒推理的测试时对抗提示调整
  • C++学习笔记(二十三)——STL标准库
  • 握手问题 第十五届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组
  • 通过C#脚本更改材质球的参数
  • Flutter TextField 从入门到精通:掌握输入框的完整指南
  • 【链表】一文搞定链表算法:从基础到实战