API 网关:Spring Cloud Gateway 的路由与过滤

Spring Cloud Gateway:您的微服务保镖兼红娘!

各位看官,大家好!今天咱们不聊风花雪月,不谈人生理想,就来聊聊微服务架构中的一个重要角色:API 网关。 别听到“微服务”就觉得高深莫测,其实它就是把一个庞大的应用拆分成一个个小的、独立的服务。 想象一下,原来一个巨无霸餐厅,现在变成了各种小吃摊,各有特色,各自为战。

但是问题来了,这么多小吃摊,顾客怎么点餐?总不能让顾客直接跟每个小吃摊老板对接吧? 这时候,就需要一个“总服务台”,统一接收顾客的订单,然后分发给对应的小吃摊,这就是 API 网关的职责。

而 Spring Cloud Gateway,就是 Spring 全家桶里提供的这个“总服务台”,它像一个尽职尽责的保镖,保护着您的微服务;又像一个热情洋溢的红娘,牵线搭桥,连接着客户端和微服务。

为什么要用 API 网关?

您可能会问,直接让客户端调用微服务不行吗? 当然可以,但是直接调用会有很多问题:

  1. 安全问题: 直接暴露微服务,很容易受到攻击,比如恶意请求、DDoS 攻击等。
  2. 复杂性: 客户端需要知道每个微服务的地址,而且如果微服务地址变更,客户端也要跟着改,维护起来很麻烦。
  3. 重复代码: 很多通用的逻辑,比如认证、授权、日志记录等,需要在每个微服务里都实现一遍,造成代码冗余。
  4. 协议转换: 不同的客户端可能使用不同的协议,比如 HTTP、WebSocket 等,微服务需要支持所有协议,增加了复杂度。
  5. 聚合请求: 客户端可能需要调用多个微服务才能完成一个业务场景,如果让客户端自己去调用,效率很低。

有了 API 网关,这些问题就迎刃而解了:

  • 统一入口: 客户端只需要跟 API 网关交互,无需关心微服务的细节。
  • 安全防护: API 网关可以进行身份验证、授权、限流等安全措施,保护微服务。
  • 路由转发: API 网关可以根据不同的规则,将请求转发到对应的微服务。
  • 协议转换: API 网关可以进行协议转换,让微服务专注于业务逻辑。
  • 请求聚合: API 网关可以将多个请求聚合成一个请求,减少客户端的请求次数。
  • 跨域处理: API 网关可以统一处理跨域问题,简化客户端的开发。
  • 监控和日志: API 网关可以记录请求和响应的日志,方便进行监控和分析。

总而言之,API 网关就像一个称职的管家,把微服务打理得井井有条,让客户端用起来舒舒服服。

Spring Cloud Gateway 的核心概念

Spring Cloud Gateway 的核心概念主要有两个:路由 (Route)过滤器 (Filter)

  • 路由 (Route): 路由是 API 网关的基本组成单元,它定义了请求应该如何转发到对应的微服务。 一个路由包含以下几个要素:

    • ID: 路由的唯一标识。
    • Predicate: 断言,用于匹配请求。只有当请求满足断言条件时,才会执行该路由。
    • Filters: 过滤器,用于对请求进行修改或增强。
    • URI: 目标 URI,即请求最终要转发到的微服务地址。
    • Order: 路由的优先级,数字越小,优先级越高。
  • 过滤器 (Filter): 过滤器是 API 网关的核心功能,它用于对请求进行各种处理,比如修改请求头、添加参数、进行认证、限流等。 过滤器可以分为两种:

    • GatewayFilter: 作用于单个路由,可以对请求和响应进行处理。
    • GlobalFilter: 作用于所有路由,通常用于实现一些通用的功能,比如日志记录、安全认证等。

简而言之,路由就是告诉 API 网关“往哪儿走”,而过滤器就是告诉 API 网关“怎么走”。

如何配置 Spring Cloud Gateway?

配置 Spring Cloud Gateway 主要有两种方式:

  1. Java 代码配置: 使用 Java 代码来定义路由和过滤器,灵活性高,适合复杂的场景。
  2. 配置文件配置: 使用 YAML 或 Properties 文件来定义路由和过滤器,简单易懂,适合简单的场景。

接下来,我们分别来看一下这两种方式的配置方法。

1. Java 代码配置

首先,需要在 Spring Boot 项目中引入 Spring Cloud Gateway 的依赖:

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

然后,创建一个配置类,使用 RouteLocatorBuilder 来定义路由:

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()
                // 第一个路由:将 /baidu 请求转发到 https://www.baidu.com
                .route("baidu_route", r -> r.path("/baidu")
                        .uri("https://www.baidu.com"))

                // 第二个路由:将 /api/user/** 请求转发到 user-service 服务,并移除 /api 前缀
                .route("user_service_route", r -> r.path("/api/user/**")
                        .filters(f -> f.stripPrefix(1))
                        .uri("lb://user-service")) // lb:// 表示使用 LoadBalancerClient 进行负载均衡

                // 第三个路由:将 /api/product/** 请求转发到 product-service 服务,并添加一个请求头
                .route("product_service_route", r -> r.path("/api/product/**")
                        .filters(f -> f.addRequestHeader("X-Request-Source", "Gateway"))
                        .uri("lb://product-service"))

                .build();
    }
}

在这个例子中,我们定义了三个路由:

  • baidu_route: 将所有以 /baidu 开头的请求转发到 https://www.baidu.com
  • user_service_route: 将所有以 /api/user/** 开头的请求转发到 user-service 服务,并使用 stripPrefix(1) 过滤器移除 /api 前缀。lb://user-service 表示使用 LoadBalancerClient 进行负载均衡,user-service 是服务的名称。
  • product_service_route: 将所有以 /api/product/** 开头的请求转发到 product-service 服务,并使用 addRequestHeader("X-Request-Source", "Gateway") 过滤器添加一个请求头 X-Request-Source: Gateway

代码解释:

  • RouteLocatorBuilder 用于构建路由。
  • route(String id, Function<PredicateSpec, AsyncBuilder>) 方法用于定义一个路由,第一个参数是路由的 ID,第二个参数是一个函数,用于定义路由的规则。
  • path(String... patterns) 方法用于定义请求路径的匹配规则,可以使用 Ant 风格的路径匹配。
  • filters(GatewayFilterSpec::filter) 方法用于定义过滤器,可以添加多个过滤器。
  • stripPrefix(int parts) 过滤器用于移除请求路径的前缀,parts 参数指定要移除的前缀的层数。
  • addRequestHeader(String headerName, String headerValue) 过滤器用于添加请求头。
  • uri(String uri) 方法用于指定目标 URI,可以使用 HTTP 地址或者 lb://service-name 格式的地址,表示使用 LoadBalancerClient 进行负载均衡。

2. 配置文件配置

除了 Java 代码配置,还可以使用 YAML 或 Properties 文件来配置 Spring Cloud Gateway。 这种方式更加简单直观,适合简单的场景。

YAML 配置文件 (application.yml):

spring:
  cloud:
    gateway:
      routes:
        - id: baidu_route
          uri: https://www.baidu.com
          predicates:
            - Path=/baidu

        - id: user_service_route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - StripPrefix=1

        - id: product_service_route
          uri: lb://product-service
          predicates:
            - Path=/api/product/**
          filters:
            - AddRequestHeader=X-Request-Source, Gateway

Properties 配置文件 (application.properties):

spring.cloud.gateway.routes[0].id=baidu_route
spring.cloud.gateway.routes[0].uri=https://www.baidu.com
spring.cloud.gateway.routes[0].predicates[0]=Path=/baidu

spring.cloud.gateway.routes[1].id=user_service_route
spring.cloud.gateway.routes[1].uri=lb://user-service
spring.cloud.gateway.routes[1].predicates[0]=Path=/api/user/**
spring.cloud.gateway.routes[1].filters[0]=StripPrefix=1

spring.cloud.gateway.routes[2].id=product_service_route
spring.cloud.gateway.routes[2].uri=lb://product-service
spring.cloud.gateway.routes[2].predicates[0]=Path=/api/product/**
spring.cloud.gateway.routes[2].filters[0]=AddRequestHeader=X-Request-Source, Gateway

配置文件中的参数与 Java 代码配置中的参数一一对应,含义相同。

代码解释:

  • spring.cloud.gateway.routes:定义路由列表。
  • id:路由的唯一标识。
  • uri:目标 URI。
  • predicates:断言列表,用于匹配请求。
  • filters:过滤器列表,用于对请求进行修改或增强。

Spring Cloud Gateway 的常用过滤器

Spring Cloud Gateway 提供了丰富的内置过滤器,可以满足各种常见的需求。 下面列举一些常用的过滤器:

过滤器名称 功能描述
AddRequestHeader 添加请求头。
AddRequestParameter 添加请求参数。
AddResponseHeader 添加响应头。
StripPrefix 移除请求路径的前缀。
PrefixPath 添加请求路径的前缀。
RewritePath 重写请求路径。
RedirectTo 重定向到指定的 URI。
Hystrix 使用 Hystrix 进行熔断降级。
Retry 重试请求。
RequestRateLimiter 限制请求速率,防止恶意请求。
TokenRelay 将 OAuth 2.0 的 Token 传递给下游服务。
RemoveRequestHeader 移除请求头
RemoveResponseHeader 移除响应头
SetPath 设置请求路径
ModifyRequestBody 修改请求体
ModifyResponseBody 修改响应体
CircuitBreaker 使用 Resilence4j 或其他断路器框架进行熔断降级

示例:使用 RequestRateLimiter 过滤器进行限流

spring:
  cloud:
    gateway:
      routes:
        - id: rate_limit_route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - RequestRateLimiter=redis-rate-limiter, replenishRate:10, burstCapacity:20 # 每秒允许 10 个请求,最大突发流量为 20 个

在这个例子中,我们使用了 RequestRateLimiter 过滤器来限制请求速率。 redis-rate-limiter 是一个基于 Redis 的限流器,replenishRate 参数指定每秒允许的请求数量,burstCapacity 参数指定最大突发流量。

注意: 使用 RequestRateLimiter 过滤器需要引入 spring-cloud-starter-gatewayspring-boot-starter-data-redis 依赖。

除了内置过滤器,还可以自定义过滤器,以满足更复杂的需求。 自定义过滤器需要实现 GatewayFilterGlobalFilter 接口,并将其注册为 Spring Bean。

总结

Spring Cloud Gateway 是一个功能强大的 API 网关,它可以帮助我们构建安全、可靠、高效的微服务架构。 通过灵活的路由和过滤器配置,我们可以实现各种各样的功能,比如安全认证、限流、请求聚合、协议转换等。

希望本文能够帮助您更好地理解和使用 Spring Cloud Gateway,让您的微服务架构更加健壮!

最后,祝各位看官工作顺利,生活愉快! 如果您觉得本文对您有所帮助,请点个赞,鼓励一下作者! 谢谢大家!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注