在 Spring Cloud 生态系统中,网关是非常重要的一个组件,它是系统对外的统一入口,承担着请求路由、过滤、负载均衡等多种功能。下面将详细介绍下Spring Cloud Gateway 。

一、概述

Spring Cloud Gateway 是 Spring Cloud 官方推出的 API 网关项目,旨在为微服务架构提供一种简单且有效的方式来路由请求,并提供了丰富的过滤器链,可对请求和响应进行拦截和处理。它基于 Spring 5、Spring Boot 2.0 和 Project Reactor 等技术构建,具有高性能和响应式的特点。

二、核心概念

1. 路由(Route)

路由是网关的基本构建块,由一个 ID、一个目标 URI、一组断言(Predicate)和一组过滤器(Filter)组成。断言用于匹配请求,当请求满足断言条件时,该路由将被激活。

2. 断言(Predicate)

在 Spring Cloud Gateway 中,断言(Predicate)是路由规则的重要组成部分,它用于匹配客户端请求的各种属性,当请求满足断言条件时,对应的路由将被激活。Spring Cloud Gateway 提供了丰富的断言工厂,下面详细介绍一些常见的断言及其使用方法。

(1)路径断言(Path Route Predicate Factory)
  • 作用:根据请求的路径进行匹配。
  • 示例配置(YAML):
spring:
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: lb://target-service
          predicates:
            - Path=/api/**

上述配置表示,所有以 /api/ 开头的请求都会匹配到该路由,并被转发到 target-service。** 是通配符,表示任意路径。

  • Java 代码配置示例:
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()
               .route("path_route", r -> r.path("/api/**")
                        .uri("lb://target-service"))
               .build();
    }
}
(2)方法断言(Method Route Predicate Factory)
  • 作用:根据请求的 HTTP 方法(如 GET、POST、PUT、DELETE 等)进行匹配。
  • 示例配置(YAML):
spring:
  cloud:
    gateway:
      routes:
        - id: method_route
          uri: lb://target-service
          predicates:
            - Method=GET,POST

此配置表示,只有 GET 或 POST 请求会匹配到该路由,并被转发到 target-service。

  • Java 代码配置示例:
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;
import org.springframework.http.HttpMethod;

@Configuration
public class GatewayConfig {
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
               .route("method_route", r -> r.method(HttpMethod.GET, HttpMethod.POST)
                        .uri("lb://target-service"))
               .build();
    }
}
(3)查询参数断言(Query Route Predicate Factory)
  • 作用:根据请求的查询参数进行匹配,可以指定参数名和可选的参数值。
  • 示例配置(YAML):
spring:
  cloud:
    gateway:
      routes:
        - id: query_route
          uri: lb://target-service
          predicates:
            - Query=page, [0-9]+

上述配置表示,当请求包含 page 参数,且参数值为一个或多个数字时,该请求会匹配到该路由,并被转发到 target-service。如果不指定参数值(如 - Query=page),则只要请求包含 page 参数即可匹配。

  • Java 代码配置示例:
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()
               .route("query_route", r -> r.query("page", "[0-9]+")
                        .uri("lb://target-service"))
               .build();
    }
}
(4)头部断言(Header Route Predicate Factory)
  • 作用:根据请求的头部信息进行匹配,可以指定头部名称和可选的头部值。
  • 示例配置(YAML):
spring:
  cloud:
    gateway:
      routes:
        - id: header_route
          uri: lb://target-service
          predicates:
            - Header=X-Request-Id, \d+

此配置表示,当请求的头部包含 X-Request-Id,且其值为一个或多个数字时,该请求会匹配到该路由,并被转发到 target-service。

  • Java 代码配置示例:
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()
               .route("header_route", r -> r.header("X-Request-Id", "\\d+")
                        .uri("lb://target-service"))
               .build();
    }
}
(1)Cookie 断言(Cookie Route Predicate Factory)
  • 作用:根据请求的 Cookie 信息进行匹配,可以指定 Cookie 名称和可选的 Cookie 值。
  • 示例配置(YAML):
spring:
  cloud:
    gateway:
      routes:
        - id: cookie_route
          uri: lb://target-service
          predicates:
            - Cookie=sessionId, [a-zA-Z0-9]+

上述配置表示,当请求的 Cookie 中包含 sessionId,且其值为一个或多个字母或数字时,该请求会匹配到该路由,并被转发到 target-service。

  • Java 代码配置示例:
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()
               .route("cookie_route", r -> r.cookie("sessionId", "[a-zA-Z0-9]+")
                        .uri("lb://target-service"))
               .build();
    }
}
(6)Host 断言(Host Route Predicate Factory)
  • 作用:根据请求的 Host 头部信息进行匹配,可以使用通配符。
  • 示例配置(YAML):
spring:
  cloud:
    gateway:
      routes:
        - id: host_route
          uri: lb://target-service
          predicates:
            - Host=**.example.com

此配置表示,当请求的 Host 头部以 .example.com 结尾时,该请求会匹配到该路由,并被转发到 target-service。

  • Java 代码配置示例:
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()
               .route("host_route", r -> r.host("**.example.com")
                        .uri("lb://target-service"))
               .build();
    }
}
(7)组合断言

可以将多个断言组合使用,只有当请求同时满足所有断言条件时,路由才会被激活。例如:

spring:
  cloud:
    gateway:
      routes:
        - id: combined_route
          uri: lb://target-service
          predicates:
            - Path=/api/**
            - Method=GET
            - Query=page, [0-9]+

此配置表示,只有当请求的路径以 /api/ 开头、HTTP 方法为 GET 且包含 page 参数(参数值为数字)时,该请求才会匹配到该路由,并被转发到 target-service。

通过合理使用这些断言,可以灵活地定义 Spring Cloud Gateway 的路由规则,满足不同的业务需求。

3. 过滤器(Filter)

Spring Cloud Gateway 的过滤器是其核心功能之一,它允许开发者在请求被路由到目标服务之前或响应返回客户端之前对请求和响应进行修改、增强或验证等操作。下面从过滤器的类型、内置过滤器、自定义过滤器以及过滤器的执行顺序等方面详细介绍。

(1)过滤器类型

Spring Cloud Gateway 中的过滤器主要分为两种类型:

路由过滤器(Route-specific Filters)
  • 作用范围:仅应用于特定的路由,通过在路由配置中显式指定来生效。每个路由可以有自己独立的路由过滤器链,用于处理该路由下的请求和响应。
  • 配置示例(YAML):
spring:
  cloud:
    gateway:
      routes:
        - id: user_route
          uri: lb://user-service
          predicates:
            - Path=/user/**
          filters:
            - AddRequestHeader=X-Request-Source, Gateway # 为该路由下的请求添加请求头
全局过滤器(Global Filters)
  • 作用范围:应用于所有的路由,无需在每个路由配置中单独指定。全局过滤器通常用于实现一些通用的处理逻辑,如日志记录、权限验证等。
  • 实现方式:通过实现 GlobalFilter 接口并使用 @Component 注解将其注册为 Spring Bean 来创建全局过滤器。示例代码如下:
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
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 CustomGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest().mutate()
               .headers(httpHeaders -> httpHeaders.add("Global-Filter-Header", "Global-Filter-Value"))
               .build();
        return chain.filter(exchange.mutate().request(request).build());
    }

    @Override
    public int getOrder() {
        return -1; // 过滤器执行顺序
    }
}
(2)内置过滤器

Spring Cloud Gateway 提供了丰富的内置过滤器,涵盖了请求和响应处理的各个方面,以下是一些常见的内置过滤器:

AddRequestHeader
  • 作用:为请求添加指定的请求头。
  • 配置示例(YAML):
filters:
  - AddRequestHeader=X-Request-Id, 12345
AddResponseHeader
  • 作用:为响应添加指定的响应头。
  • 配置示例(YAML):
filters:
  - AddResponseHeader=X-Response-Info, Processed-by-Gateway
RewritePath
  • 作用:重写请求的路径。
  • 配置示例(YAML):
filters:
  - RewritePath=/api/(?<segment>.*), /$\{segment} # 将 /api/ 后面的部分提取并替换原路径
RequestRateLimiter
  • 作用:对请求进行限流,防止过多请求涌入后端服务。
  • 配置示例(YAML):
filters:
  - name: RequestRateLimiter
    args:
      redis-rate-limiter.replenishRate: 10 # 每秒允许的请求数
      redis-rate-limiter.burstCapacity: 20 # 最大突发请求数
      key-resolver: "#{@userKeyResolver}" # 限流的键解析器
(3)自定义过滤器

除了使用内置过滤器,开发者还可以根据业务需求自定义过滤器。自定义过滤器需要实现 GatewayFilter 或 GlobalFilter 接口,并实现 filter 方法。以下是一个自定义路由过滤器的示例:

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
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 CustomRouteFilter implements GatewayFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest().mutate()
               .headers(httpHeaders -> httpHeaders.add("Custom-Filter-Header", "Custom-Filter-Value"))
               .build();
        return chain.filter(exchange.mutate().request(request).build());
    }

    @Override
    public int getOrder() {
        return 0; // 过滤器执行顺序
    }
}
(4)过滤器的执行顺序

过滤器的执行顺序由 Ordered 接口的 getOrder 方法或 @Order 注解指定,返回值越小的过滤器越先执行。全局过滤器和路由过滤器会合并成一个过滤器链,按照顺序依次执行。通常,全局过滤器会在路由过滤器之前执行。

通过合理使用内置过滤器和自定义过滤器,开发者可以灵活地对请求和响应进行处理,满足各种复杂的业务需求。

三、工作原理

Spring Cloud Gateway 的工作原理主要基于路由匹配和过滤器链,工作流程如下:

1. 请求接收

客户端的请求首先到达 Spring Cloud Gateway,Gateway 作为系统的统一入口,负责接收所有客户端的 HTTP 或 WebSocket 请求。

2. 路由匹配

Gateway 接收到请求后,会根据配置的路由规则进行匹配。匹配过程如下:

  • 获取路由定义:从路由定义源(如配置文件、数据库或动态路由管理系统)中获取所有的路由定义。
  • 遍历路由断言:依次检查每个路由的断言,判断请求是否满足断言条件。如果请求满足某个路由的所有断言,则该路由被激活。例如,以下是一个基于路径断言的路由配置:
spring:
  cloud:
    gateway:
      routes:
        - id: user_route
          uri: lb://user-service
          predicates:
            - Path=/user/**

当请求的路径以 /user/ 开头时,该路由将被激活。

3. 过滤器链处理

一旦路由匹配成功,请求将进入过滤器链进行处理。过滤器链的处理过程如下:

  • 过滤器排序:根据过滤器的顺序(通过 Ordered 接口或 @Order 注解指定)对过滤器进行排序。
  • 前置过滤器处理:请求首先经过所有的前置过滤器,前置过滤器可以对请求进行修改、验证、添加请求头或参数等操作。例如,添加一个自定义的请求头:
spring:
  cloud:
    gateway:
      routes:
        - id: user_route
          uri: lb://user-service
          predicates:
            - Path=/user/**
          filters:
            - AddRequestHeader=X-Request-Source, Gateway
  • 请求转发:经过前置过滤器处理后,请求被转发到目标服务。如果使用 lb:// 前缀指定目标 URI,Spring Cloud Gateway 会使用 Spring Cloud LoadBalancer 进行负载均衡,选择一个合适的服务实例进行请求转发。
  • 后置过滤器处理:目标服务处理请求并返回响应后,响应会经过所有的后置过滤器。后置过滤器可以对响应进行修改、添加响应头、记录日志等操作。
4. 响应返回

经过过滤器链处理后,最终的响应被返回给客户端。

四、配置与使用

Spring Cloud Gateway 的路由规则配置可以通过多种方式实现,下面分别介绍使用 YAML 配置文件、Java 代码以及动态路由配置的方法。

1. 使用 YAML 配置文件配置路由规则

这是最常见、最简便的配置方式,在 application.yml 或 application.properties 中进行配置。以下是一个详细的 application.yml 配置示例:

spring:
  cloud:
    gateway:
      routes:
        # 第一个路由规则
        - id: order_service_route
          uri: lb://order-service # 使用 lb:// 前缀表示使用 Spring Cloud LoadBalancer 进行负载均衡,目标服务名为 order-service
          predicates:
            - Path=/order/** # 路径断言,匹配所有以 /order/ 开头的请求
            - Method=GET # 方法断言,只允许 GET 请求
          filters:
            - AddRequestHeader=X-Request-Source, Gateway # 添加请求头,键为 X-Request-Source,值为 Gateway
            - RewritePath=/order/(?<segment>.*), /$\{segment} # 重写请求路径,将 /order/ 后面的部分提取并替换原路径
        # 第二个路由规则
        - id: product_service_route
          uri: http://product-service.example.com # 直接指定目标服务的 URI
          predicates:
            - Query=category, electronics # 查询参数断言,当请求包含 category=electronics 参数时匹配
          filters:
            - AddResponseHeader=X-Response-Info, Processed-by-Gateway # 添加响应头,键为 X-Response-Info,值为 Processed-by-Gateway

上述配置中定义了两个路由规则:

  • order_service_route:匹配以 /order/ 开头的 GET 请求,将其路由到 order-service 服务,并添加请求头和重写请求路径。
  • product_service_route:匹配包含 category=electronics 查询参数的请求,将其路由到 http://product-service.example.com,并添加响应头。
2. 使用 Java 代码配置路由规则

除了 YAML 配置文件,还可以使用 Java 代码来配置路由规则。创建一个配置类,通过 RouteLocator Bean 来定义路由。示例代码如下:

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()
               .route("user_service_route", r -> r
                        .path("/user/**") // 路径断言
                        .and().method("POST") // 方法断言,只允许 POST 请求
                        .uri("lb://user-service") // 目标服务名为 user-service
                )
               .route("payment_service_route", r -> r
                        .query("type", "online") // 查询参数断言,当请求包含 type=online 参数时匹配
                        .uri("http://payment-service.example.com") // 直接指定目标服务的 URI
                )
               .build();
    }
}

在上述代码中,定义了两个路由规则:

  • user_service_route:匹配以 /user/ 开头的 POST 请求,将其路由到 user-service 服务。
  • payment_service_route:匹配包含 type=online 查询参数的请求,将其路由到 http://payment-service.example.com。
3. 动态路由配置

在某些场景下,需要动态地添加、修改或删除路由规则。可以通过实现 RouteDefinitionRepository 接口来自定义路由定义仓库,从而实现动态路由配置。以下是一个简单的示例:

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.ArrayList;
import java.util.List;

@Component
public class CustomRouteDefinitionRepository implements RouteDefinitionRepository {
    private final List<RouteDefinition> routeDefinitions = new ArrayList<>();

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        return Flux.fromIterable(routeDefinitions);
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return route.doOnNext(routeDefinitions::add).then();
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return routeId.doOnNext(id -> routeDefinitions.removeIf(rd -> rd.getId().equals(id))).then();
    }
}

然后可以在需要的地方注入 CustomRouteDefinitionRepository,并调用其 save 和 delete 方法来动态管理路由规则。

通过以上三种方式,可以根据实际需求灵活配置 Spring Cloud Gateway 的路由规则。

4. 自定义过滤器

通过实现 GatewayFilter 或 GlobalFilter 接口来创建自定义过滤器。以下是一个简单的自定义全局过滤器示例:

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
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 CustomGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest().mutate()
               .headers(httpHeaders -> httpHeaders.add("Custom-Header", "Custom-Value"))
               .build();
        return chain.filter(exchange.mutate().request(request).build());
    }

    @Override
    public int getOrder() {
        return -1; // 过滤器执行顺序
    }
}

五、优势

Spring Cloud Gateway 作为 Spring Cloud 生态中的 API 网关组件,具备多方面的显著优势,以下为你详细阐述:

1. 技术架构层面
  • 响应式编程模型:基于 Spring 5、Spring Boot 2.0 和 Project Reactor 构建,采用响应式编程模型。这种模型使得 Spring Cloud Gateway 能够以异步、非阻塞的方式处理请求,在高并发场景下可以高效地利用系统资源,提升系统的吞吐量和响应性能,尤其适合处理大量的短连接请求。
  • 与 Spring Cloud 生态无缝集成:它是 Spring Cloud 体系的一部分,能与 Spring Cloud 中的其他组件(如服务注册中心 Eureka、Nacos,负载均衡器 Spring Cloud LoadBalancer,熔断机制 Resilience4j 等)进行无缝集成。这种紧密的集成使得开发者可以轻松构建出完整的微服务架构,实现服务的注册、发现、调用和管理等功能。
2. 功能特性层面
  • 灵活的路由配置:支持多种方式配置路由规则,既可以通过 YAML 配置文件进行静态配置,也能使用 Java 代码进行动态配置,甚至可以实现动态路由管理。同时,提供了丰富的路由断言工厂,如基于请求路径、请求方法、请求参数、请求头、Cookie 等进行匹配,能够根据不同的业务需求灵活定义路由规则。
  • 强大的过滤器功能:拥有丰富的内置过滤器,涵盖了请求和响应的修改、参数的添加与修改、请求的限流、熔断、重试等功能。并且支持自定义过滤器,开发者可以根据特定的业务逻辑编写自己的过滤器,对请求和响应进行定制化处理,满足多样化的业务需求。
  • 支持多种协议:能够处理多种不同的协议,包括 HTTP、WebSocket 等。这使得它可以作为统一的入口,处理不同类型的客户端请求,方便构建多样化的应用系统。
3. 开发运维层面
  • 简化开发流程:作为微服务架构的统一入口,Spring Cloud Gateway 为客户端提供了统一的 API 接口,简化了客户端与各个微服务之间的交互流程。客户端只需与网关进行通信,无需关心后端具体的微服务实现和部署细节,降低了开发的复杂度。
  • 便于管理和维护:集中管理所有的路由规则和过滤器,使得系统的配置和管理更加方便。同时,通过网关可以对所有的请求进行统一的监控和日志记录,方便运维人员进行问题排查和系统性能优化。
4. 安全层面
  • 安全控制:可以在网关层面实现一些基本的安全控制,如身份验证、授权、IP 访问控制等。通过过滤器机制,可以对请求进行拦截和验证,确保只有合法的请求才能访问后端微服务,提高系统的安全性。

关于Spring Cloud的学习视频放这了
链接: https://pan.baidu.com/s/1nVzqOlqySHgw53cuZ3ZF-Q?pwd=mkvt 提取码: mkvt

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐