Spring Cloud Gateway 教程:实现路由、过滤与负载均衡 – wiki基地

I sincerely apologize for the repeated issues in using the write_file tool. There seems to be a persistent problem preventing me from writing to a file directly.

To ensure you receive the article, I will now output the entire content of the “Spring_Cloud_Gateway_Tutorial.md” article directly in my response.

“`markdown

Spring Cloud Gateway 教程:实现路由、过滤与负载均衡

在微服务架构中,API 网关扮演着至关重要的角色,它是所有客户端请求的入口点。API 网关不仅负责请求路由,还可以进行认证、授权、流量管理、熔断、限流等操作。Spring Cloud Gateway 是 Spring 生态系统中的一个 API 网关解决方案,它基于 Spring 5、Project Reactor 和 Spring Boot 2 构建,提供了高性能、响应式的特性。

本教程将详细介绍如何使用 Spring Cloud Gateway 实现请求的路由、过滤以及与服务发现结合的负载均衡。

1. Spring Cloud Gateway 简介

Spring Cloud Gateway 旨在提供一种简单而有效的方式来构建 API 网关。它的核心理念是:所有请求都通过网关,然后根据预定义的路由规则转发到后端服务。

主要特性:
* 响应式编程模型:基于 Reactor,处理高并发请求时表现出色。
* 路由: 灵活的路由配置,支持多种匹配条件。
* 过滤器: 强大的请求/响应处理能力,可以在请求到达后端服务之前或响应返回客户端之前进行处理。
* 负载均衡: 与 Spring Cloud 服务发现无缝集成。
* 熔断: 支持集成 Hystrix 或 Resilience4j。

2. 核心概念

在使用 Spring Cloud Gateway 之前,理解其三个核心概念至关重要:

  • Route (路由):路由是网关的基本构建块。它由一个 ID、一个目标 URI、一组谓词 (Predicate) 和一组过滤器 (Filter) 组成。当请求与谓词匹配时,它将被转发到目标 URI。
  • Predicate (谓词):谓词是路由匹配条件。它们定义了什么样的请求应该被路由到哪个目标 URI。例如,Path 谓词可以匹配请求的路径,Method 谓词可以匹配请求的 HTTP 方法。
  • Filter (过滤器):过滤器允许在请求被代理到目标服务之前或响应返回到客户端之前修改请求和响应。它们可以用于添加请求头、修改路径、执行认证、日志记录等。

3. 搭建一个基本的网关服务

首先,我们需要创建一个 Spring Boot 项目并引入 Spring Cloud Gateway 依赖。

步骤 1: 创建 Spring Boot 项目
可以使用 Spring Initializr (start.spring.io) 创建一个 Maven 或 Gradle 项目。
添加以下依赖:
* Spring WebFlux (Spring Cloud Gateway 是响应式的,需要 WebFlux)
* Spring Cloud Gateway

pom.xml 示例:

“`xml


4.0.0 org.springframework.boot
spring-boot-starter-parent
2.7.18
com.example
gateway-service
0.0.1-SNAPSHOT
gateway-service
Demo project for Spring Cloud Gateway

<properties>
    <java.version>11</java.version>
    <spring-cloud.version>2021.0.9</spring-cloud.version> <!-- 请根据实际情况选择合适的版本 -->
</properties>

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

“`

步骤 2: 主应用程序类
Spring Cloud Gateway 应用程序是一个标准的 Spring Boot 应用程序。

“`java
package com.example.gatewayservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class GatewayServiceApplication {

public static void main(String[] args) {
    SpringApplication.run(GatewayServiceApplication.class, args);
}

}
“`

4. 实现路由 (Routing)

路由是 Spring Cloud Gateway 的核心功能。可以通过配置文件或 Java 代码两种方式进行配置。

4.1 配置文件方式 (推荐)

application.ymlapplication.properties 中配置路由。

application.yml 示例:

“`yaml
server:
port: 8080 # 网关服务端口

spring:
cloud:
gateway:
routes:
– id: service_route_1 # 路由ID,唯一标识
uri: http://localhost:8081 # 目标URI,可以直接指向后端服务地址
predicates:
– Path=/service1/ # 当请求路径匹配 /service1/ 时进行路由
filters:
– RewritePath=/service1/(?.), /${segment} # 重写路径,将 /service1/xxx 变为 /xxx
– id: service_route_2
uri: http://localhost:8082
predicates:
– Host=
.somehost.com # 当请求的Host头匹配 *.somehost.com 时路由
– Method=GET,POST # 当请求方法是 GET 或 POST 时路由
filters:
– AddRequestHeader=X-Request-Color, blue # 添加请求头
“`

常用的谓词 (Predicate Factories):

  • After: 请求在特定时间之后发生。
  • Before: 请求在特定时间之前发生。
  • Between: 请求在两个特定时间之间发生。
  • Cookie: 匹配请求中包含指定名称和值的 Cookie。
  • Header: 匹配请求头中包含指定名称和值的 Header。
  • Host: 匹配请求的 Host 头。
  • Method: 匹配请求的 HTTP 方法(GET, POST, PUT, DELETE 等)。
  • Path: 匹配请求的 URI 路径。
  • Query: 匹配请求中包含指定名称和值的查询参数。
  • RemoteAddr: 匹配请求的远程 IP 地址。
  • Weight: 根据权重分配流量(实现灰度发布等)。

4.2 Java 代码方式

可以通过 RouteLocator Bean 来配置路由。

“`java
package com.example.gatewayservice;

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("java_route_1", r -> r.path("/java/service1/**")
                    .filters(f -> f.rewritePath("/java/service1/(?<segment>.*)", "/${segment}"))
                    .uri("http://localhost:8081"))
            .route("java_route_2", r -> r.host("**.javahost.com")
                    .and().method("GET", "POST")
                    .filters(f -> f.addRequestHeader("X-Java-Request", "true"))
                    .uri("http://localhost:8082"))
            .build();
}

}
“`

5. 实现过滤 (Filtering)

过滤器是 Spring Cloud Gateway 的强大之处,允许你对进入网关的请求和从后端服务返回的响应进行修改。过滤器分为两种:

  1. GatewayFilter: 作用于单个路由或特定路由组。
  2. GlobalFilter: 作用于所有路由。

5.1 GatewayFilter (路由级别过滤器)

Spring Cloud Gateway 提供了许多内置的 GatewayFilter 工厂,你可以在 application.yml 或 Java 配置中直接使用。

常用的 GatewayFilter 工厂:

  • AddRequestHeader: 在请求转发到后端服务前添加请求头。
  • AddResponseHeader: 在响应返回给客户端前添加响应头。
  • RewritePath: 重写请求路径。
  • PrefixPath: 给请求路径添加前缀。
  • StripPrefix: 从请求路径中移除指定数量的前缀。
  • Retry: 重试失败的请求。
  • CircuitBreaker: 集成熔断器 (例如 Resilience4j)。
  • RequestRateLimiter: 请求速率限制。

application.yml 示例 (已在路由部分展示,这里再强调):

yaml
spring:
cloud:
gateway:
routes:
- id: service_with_filters
uri: http://localhost:8081
predicates:
- Path=/api/**
filters:
- AddRequestHeader=X-Custom-Header, MyValue # 添加自定义请求头
- AddResponseHeader=X-Custom-Response-Header, MyResponseValue # 添加自定义响应头
- RewritePath=/api/(?<segment>.*), /${segment} # 将 /api/xxx 重写为 /xxx
- StripPrefix=1 # 移除路径的第一个部分,等同于 RewritePath 简化形式

5.2 自定义 GlobalFilter

如果你需要一个作用于所有路由的全局逻辑,或者内置过滤器无法满足你的需求,可以实现 GlobalFilter 接口。

“`java
package com.example.gatewayservice;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class CustomGlobalPreFilter implements GlobalFilter, Ordered {

private static final Logger log = LoggerFactory.getLogger(CustomGlobalPreFilter.class);

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    log.info("CustomGlobalPreFilter executed. Path: {}", exchange.getRequest().getPath());

    // 示例:简单的认证逻辑
    String token = exchange.getRequest().getHeaders().getFirst("Authorization");
    if (token == null || !token.startsWith("Bearer ")) {
        log.warn("Missing or invalid Authorization header. Blocking request.");
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().setComplete(); // 终止请求
    }

    // 继续过滤器链
    return chain.filter(exchange).then(Mono.fromRunnable(() -> {
        // 这里可以处理响应
        log.info("CustomGlobalPostFilter executed. Response status: {}", exchange.getResponse().getStatusCode());
    }));
}

@Override
public int getOrder() {
    // 数字越小,优先级越高
    return -1;
}

}
“`

在上面的例子中,CustomGlobalPreFilter 会在请求到达任何路由之前执行,检查 Authorization 头。如果没有有效的 Token,请求将被拒绝。Ordered 接口用于指定过滤器的执行顺序。

6. 实现负载均衡 (Load Balancing)

Spring Cloud Gateway 与 Spring Cloud LoadBalancer (或 Ribbon, 如果你使用的是旧版本) 和服务发现组件 (如 Eureka、Consul、Nacos) 集成,可以实现服务的自动负载均衡。

6.1 集成服务发现

以 Eureka 为例,首先需要搭建一个 Eureka Server,并在网关服务和后端服务中引入 Eureka Client 依赖。

步骤 1: 网关服务添加 Eureka Client 依赖

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

步骤 2: 配置 application.yml 启用服务发现

“`yaml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka # Eureka Server 地址
instance:
hostname: localhost
server:
port: 8080

spring:
application:
name: gateway-service # 网关服务注册到Eureka的名称
cloud:
gateway:
routes:
– id: user_service_route # 路由ID
uri: lb://USER-SERVICE # 使用 lb:// 前缀,Spring Cloud LoadBalancer 会根据服务名自动进行负载均衡
predicates:
– Path=/users/ # 匹配 /users/ 的请求
filters:
– RewritePath=/users/(?.*), /${segment} # 重写路径,转发到 USER-SERVICE
“`

步骤 3: 启动类添加 @EnableDiscoveryClient 注解

“`java
package com.example.gatewayservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; // 注意这个注解

@SpringBootApplication
@EnableDiscoveryClient // 启用服务发现客户端
public class GatewayServiceApplication {

public static void main(String[] args) {
    SpringApplication.run(GatewayServiceApplication.class, args);
}

}
“`

步骤 4: 后端服务注册到 Eureka

假设你有一个名为 user-service 的后端服务,也需要引入 spring-cloud-starter-netflix-eureka-client 依赖,并在 application.yml 中配置其注册信息:

“`yaml
server:
port: 8081 # user-service 端口

spring:
application:
name: USER-SERVICE # 必须与网关路由中的服务名保持一致 (lb://USER-SERVICE)
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka
“`

当有多个 USER-SERVICE 实例注册到 Eureka 时,Spring Cloud Gateway 会自动通过 lb:// 前缀识别,并使用 Spring Cloud LoadBalancer 来选择一个健康的 USER-SERVICE 实例来处理请求。

7. 结论

Spring Cloud Gateway 提供了一个强大、灵活且高性能的 API 网关解决方案。通过其响应式的特性、丰富的谓词和过滤器,以及与 Spring Cloud 生态系统的无缝集成,开发者可以轻松构建出满足复杂微服务架构需求的网关。

本教程涵盖了 Spring Cloud Gateway 的基本设置、路由配置(包括配置文件和 Java 代码方式)、路由级别和全局过滤器的实现,以及如何与服务发现结合实现负载均衡。掌握这些概念和实践,将使你能够有效地管理和保护你的微服务。
“`

滚动至顶部