第六章:Spring Cloud Gateway网关

理论讲解

什么是API网关?
API网关就像是公司的前台接待处,所有外部请求都要先经过网关,由网关负责路由到相应的部门(微服务)。

网关可以统一处理认证、限流、监控、安全等跨切面关注点。

Spring Cloud Gateway的特点:

  • 基于Spring WebFlux,非阻塞异步模型,性能高
  • 支持动态路由、限流、熔断、重试等功能
  • 使用谓词(Predicate)和过滤器(Filter)实现灵活的路由规则

应用场景举例:
想象一个购物中心:

  • 顾客从大门进入(统一入口)
  • 根据指示牌(路由规则)找到不同的店铺(微服务)
  • 大门保安检查会员卡(身份认证)
  • 人流高峰期限制进入人数(限流)
  • 临时关闭某个区域(熔断)

项目结构

chapter-06-gateway/
├── eureka-server/           # 注册中心
├── user-service/           # 用户服务
├── product-service/        # 商品服务
├── order-service/          # 订单服务
├── payment-service/        # 支付服务
└── api-gateway/            # API网关(新增)

完整代码实现

1. API Gateway网关服务

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <parent>
    <artifactId>springcloud-course</artifactId>
    <groupId>com.lihaozhe</groupId>
    <version>1.0.0</version>
  </parent>
  <modelVersion>4.0.0</modelVersion>

  <artifactId>api-gateway</artifactId>

  <dependencies>
    <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>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
      <groupId>io.github.resilience4j</groupId>
      <artifactId>resilience4j-spring-boot3</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>
应用启动类
package com.lihaozhe.apigateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * API网关应用启动类
 * 使用Spring Cloud Gateway作为API网关,统一入口
 * 网关作为所有外部请求的统一入口,负责路由、过滤、安全等
 *
 * @author 李昊哲
 * @version 1.0.0
 */
@SpringBootApplication
@EnableDiscoveryClient
public class ApiGatewayApplication {
  public static void main(String[] args) {
    SpringApplication.run(ApiGatewayApplication.class, args);
  }
}
网关配置类
package com.lihaozhe.apigateway.config;

import com.lihaozhe.apigateway.filter.AuthFilter;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter;
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.context.annotation.Primary;
import org.springframework.http.HttpMethod;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

/**
 * 网关路由配置类
 * 配置路由规则、过滤器、谓词等
 * <p>
 * 网关核心概念:
 * - Route: 路由信息,包含ID、目标URI、谓词集合、过滤器集合
 * - Predicate: 谓词,用于匹配请求的条件
 * - Filter: 过滤器,用于修改请求和响应
 */
@Configuration
public class GatewayConfig {

  /**
   * 自定义路由规则
   * 可以配置基于路径、头部、参数、时间等的路由规则
   */
  @Bean
  public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    // 构建路由规则
    return builder.routes()
        // 用户服务路由 - 路径匹配方式
        .route("user-service-route", r -> r.path("/api/users/**")
            // 添加过滤器链
            .filters(f -> f
                // 去掉路径的第一部分(/api)
                .stripPrefix(1)
                // 添加请求头 X-Request-Source,值为 gateway
                .addRequestHeader("X-Request-Source", "gateway")
                // 添加请求头 X-Request-Time,值为当前时间戳
                .addRequestHeader("X-Request-Time", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                // 添加响应头 X-Response-Time,值为当前时间戳
                .addResponseHeader("X-Response-Time", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))))
            // 设置目标服务URI,lb://表示使用负载均衡
            .uri("lb://user-service"))

        // 商品服务路由 - 路径匹配 + 方法限制
        .route("product-service-route", r -> r.path("/api/products/**")
            // 添加方法限制谓词,只允许GET、POST、PUT方法
            .and().method(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT)
            // 添加过滤器链
            .filters(f -> f
                // 去掉路径的第一部分(/api)
                .stripPrefix(1)
                // 添加请求头 X-Request-Source,值为 gateway
                .addRequestHeader("X-Request-Source", "gateway")
                // 配置限流过滤器
                .requestRateLimiter(config -> config
                    // 设置限流器
                    .setRateLimiter(redisRateLimiter())
                    // 设置限流键解析器
                    .setKeyResolver(apiKeyResolver()))
                // 配置重试机制
                .retry(config -> config
                    // 设置重试次数为3次
                    .setRetries(3)
                    // 设置只对GET方法进行重试
                    .setMethods(HttpMethod.GET)))
            // 设置目标服务URI
            .uri("lb://product-service"))

        // 订单服务路由 - 路径匹配 + 头部验证
        .route("order-service-route", r -> r.path("/api/orders/**")
            // 添加头部验证谓词,要求请求头中包含 X-Require-Auth: true
            .and().header("X-Require-Auth", "true")
            // 添加过滤器链
            .filters(f -> f
                // 去掉路径的第一部分(/api)
                .stripPrefix(1)
                // 添加请求头 X-Request-Source,值为 gateway
                .addRequestHeader("X-Request-Source", "gateway")
                // 添加自定义认证过滤器
                .filter(new AuthFilter().apply(new AuthFilter.Config())))
            // 设置目标服务URI
            .uri("lb://order-service"))

        // 支付服务路由 - 路径匹配 + 时间限制(工作时间)
        .route("payment-service-route", r -> r.path("/api/payments/**")
            // 添加谓词,限制只有在工作时间(9:00-18:00)才能访问
            .and().predicate(serverWebExchange -> {
              // 获取当前小时数(东八区)
              int hour = LocalDateTime.now(ZoneId.of("Asia/Shanghai")).getHour();
              // 判断是否在工作时间内
              return hour >= 9 && hour < 18;
            })
            // 添加过滤器链
            .filters(f -> f
                // 去掉路径的第一部分(/api)
                .stripPrefix(1)
                // 添加请求头 X-Request-Source,值为 gateway
                .addRequestHeader("X-Request-Source", "gateway"))
            // 设置目标服务URI
            .uri("lb://payment-service"))

        // 静态资源路由
        .route("static-resource-route", r -> r.path("/static/**")
            // 添加过滤器链
            .filters(f -> f
                // 添加响应头 X-Static-Resource,值为 true
                .addResponseHeader("X-Static-Resource", "true")
                // 设置响应头 Cache-Control,启用缓存
                .setResponseHeader("Cache-Control", "public, max-age=3600"))
            // 设置静态资源服务器URI
            .uri("http://localhost:8088"))

        // 默认路由 - 服务发现自动路由
        .route("default-route", r -> r.path("/**")
            // 设置默认路由到用户服务
            .uri("lb://user-service"))
        // 构建完成并返回路由定位器
        .build();
  }

  /**
   * Redis限流器(需要Redis服务器)
   * 实际生产环境需要配置Redis连接
   */
  @Bean
  public RedisRateLimiter redisRateLimiter() {
    // 默认配置:每秒10个请求,桶容量20
    return new RedisRateLimiter(10, 20);
  }

  /**
   * 限流键解析器
   * 根据不同的策略生成限流key
   */
  @Bean
  @Primary
  public KeyResolver apiKeyResolver() {
    // 根据用户IP限流
    return exchange -> Mono.just(
        exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
    );
  }

  /**
   * 用户限流键解析器(按用户ID限流)
   */
  @Bean
  public KeyResolver userKeyResolver() {
    return exchange -> {
      // 从请求头或token中提取用户ID
      String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
      // 如果未获取到用户ID,则使用匿名用户
      if (userId == null) {
        userId = "anonymous";
      }
      // 返回用户ID作为限流键
      return Mono.just(userId);
    };
  }

  /**
   * 路径限流键解析器(按路径限流)
   */
  @Bean
  public KeyResolver pathKeyResolver() {
    return exchange -> Mono.just(
        exchange.getRequest().getPath().value()
    );
  }
}
自定义过滤器
认证过滤器
package com.lihaozhe.apigateway.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 reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.List;

/**
 * 自定义认证过滤器
 * 验证请求是否具有有效的认证信息
 *
 * @author 李昊哲
 * @version 1.0.0
 */
@Component
public class AuthFilter extends AbstractGatewayFilterFactory<AuthFilter.Config> {

  public AuthFilter() {
    super(Config.class);
  }

  @Override
  public GatewayFilter apply(Config config) {
    return (exchange, chain) -> {
      // 检查请求头中是否包含认证信息
      String authHeader = exchange.getRequest().getHeaders().getFirst("Authorization");

      // 简单的认证检查(实际项目中应该使用JWT或其他认证机制)
      if (authHeader == null || !authHeader.startsWith("Bearer ")) {
        // 认证失败,返回401 Unauthorized
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        exchange.getResponse().getHeaders().add("WWW-Authenticate", "Bearer realm=\"api-gateway\"");

        return exchange.getResponse().setComplete();
      }

      // 认证成功,继续执行下一个过滤器
      return chain.filter(exchange);
    };
  }

  @Override
  public List<String> shortcutFieldOrder() {
    return Collections.singletonList("required");
  }

  public static class Config {
    private boolean required = true;

    public boolean isRequired() {
      return required;
    }

    public void setRequired(boolean required) {
      this.required = required;
    }
  }

  @Override
  public String name() {
    return "Auth";
  }
}
日志过滤器
package com.lihaozhe.apigateway.filter;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.time.Instant;

/**
 * 全局日志过滤器
 * 记录所有请求的访问日志和性能指标
 * <p>
 * 过滤器执行顺序:
 * - 数值越小优先级越高
 * - 可以通过Ordered接口或@Order注解控制
 *
 * @author 李昊哲
 * @version 1.0.0
 */
@Component
public class LoggingFilter implements GlobalFilter, Ordered {

  private static final String START_TIME = "startTime";

  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    // 请求开始前记录时间
    exchange.getAttributes().put(START_TIME, Instant.now());

    String path = exchange.getRequest().getPath().value();
    String method = exchange.getRequest().getMethod().name();
    String remoteAddress = exchange.getRequest().getRemoteAddress() != null ?
        exchange.getRequest().getRemoteAddress().toString() : "unknown";

    System.out.printf(">>> 网关收到请求: %s %s from %s%n", method, path, remoteAddress);

    return chain.filter(exchange).then(Mono.fromRunnable(() -> {
      // 请求完成后记录日志
      Instant startTime = exchange.getAttribute(START_TIME);
      if (startTime != null) {
        long duration = Duration.between(startTime, Instant.now()).toMillis();

        int status = exchange.getResponse().getStatusCode() != null ?
            exchange.getResponse().getStatusCode().value() : 0;

        System.out.printf("<<< 网关处理完成: %s %s - Status: %d - Time: %dms%n", method, path, status, duration);

        // 记录到监控系统(这里简单打印)
        if (duration > 1000) {
          System.out.printf("!!! 慢请求警告: %s %s 耗时 %dms%n", method, path, duration);
        }
      }
    }));
  }

  @Override
  public int getOrder() {
    // 高优先级,最先执行
    return Ordered.HIGHEST_PRECEDENCE;
  }
}
限流过滤器
package com.lihaozhe.apigateway.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 reactor.core.publisher.Mono;

import java.util.List;

/**
 * 自定义限流过滤器
 * 基于IP或用户进行限流控制
 *
 * @author 李昊哲
 * @version 1.0.0
 */
@Component
public class RateLimitFilter extends AbstractGatewayFilterFactory<RateLimitFilter.Config> {

  public RateLimitFilter() {
    super(Config.class);
  }

  @Override
  public GatewayFilter apply(Config config) {
    return (exchange, chain) -> {
      String ip = exchange.getRequest().getRemoteAddress() != null ?
          exchange.getRequest().getRemoteAddress().getAddress().getHostAddress() : "unknown";

      String path = exchange.getRequest().getPath().value();

      // 简单的内存限流实现(生产环境应该使用Redis)
      if (isRateLimited(ip, path, config)) {
        // 返回限流错误
        exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
        exchange.getResponse().getHeaders().add("X-RateLimit-Limit", String.valueOf(config.getRequestsPerMinute()));
        exchange.getResponse().getHeaders().add("X-RateLimit-Retry-After", "60");

        return exchange.getResponse().writeWith(
            Mono.just(exchange.getResponse().bufferFactory().wrap(
                "{\"error\": \"Rate limit exceeded\", \"message\": \"Too many requests\"}".getBytes()
            ))
        );
      }

      return chain.filter(exchange);
    };
  }

  /**
   * 简单的内存限流检查
   */
  private boolean isRateLimited(String ip, String path, Config config) {
    String key = ip + ":" + path;
    long currentTime = System.currentTimeMillis();
    long windowStart = currentTime - 60000; // 1分钟窗口

    // 这里应该使用Redis或分布式缓存
    // 简化实现:总是返回false
    return false;
  }

  @Override
  public List<String> shortcutFieldOrder() {
    return java.util.Arrays.asList("requestsPerMinute", "burstCapacity");
  }

  public static class Config {
    private int requestsPerMinute = 100;  // 每分钟请求数
    private int burstCapacity = 50;       // 突发容量

    public int getRequestsPerMinute() {
      return requestsPerMinute;
    }

    public void setRequestsPerMinute(int requestsPerMinute) {
      this.requestsPerMinute = requestsPerMinute;
    }

    public int getBurstCapacity() {
      return burstCapacity;
    }

    public void setBurstCapacity(int burstCapacity) {
      this.burstCapacity = burstCapacity;
    }
  }
}
降级处理控制器
package com.lihaozhe.apigateway.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * 网关降级处理控制器
 * 当后端服务不可用时返回友好的降级响应
 *
 * @author 李昊哲
 * @version 1.0.0
 */
@RestController
@RequestMapping("/fallback")
public class FallbackController {

  /**
   * 降级处理
   *
   * @return 降级响应
   */
  @GetMapping("/fallback")
  public Map<String, Object> fallback() {
    return Map.of(
        "code", "503",
        "message", "服务暂时不可用,请稍后重试",
        "timestamp", System.currentTimeMillis()
    );
  }

  /**
   * 服务降级
   *
   * @return 降级响应
   */
  @GetMapping("/service-fallback")
  public Map<String, Object> serviceFallback() {
    return Map.of(
        "code", "503",
        "message", "服务暂时不可用,请稍后重试",
        "timestamp", System.currentTimeMillis()
    );
  }
}
网关健康检查控制器
package com.lihaozhe.apigateway.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

/**
 * 网关状态控制器
 * 提供网关状态检查和服务信息查询
 *
 * @author 李昊哲
 * @version 1.0.0
 */
@RestController
@RequestMapping("/gateway")
public class GatewayStatusController {

  @Autowired
  private DiscoveryClient discoveryClient;

  /**
   * 网关状态信息
   * GET /gateway/status
   *
   * @return 网关状态信息
   */
  @GetMapping("/status")
  public Map<String, Object> gatewayStatus() {
    return Map.of(
        "gateway", "UP",
        "timestamp", System.currentTimeMillis()
    );
  }

  /**
   * 获取注册的服务列表
   * GET /gateway/services
   *
   * @return 服务列表
   */
  @GetMapping("/services")
  public Map<String, Object> getServices() {
    List<String> services = discoveryClient.getServices();
    return Map.of(
        "totalServices", services.size(),
        "services", services
    );
  }

  /**
   * 健康检查
   * GET /gateway/health
   *
   * @return 健康状态
   */
  @GetMapping("/health")
  public Map<String, Object> health() {
    return Map.of(
        "status", "UP",
        "service", "api-gateway",
        "timestamp", System.currentTimeMillis()
    );
  }
}
网关配置文件
server:
  port: 8080

spring:
  application:
    name: api-gateway
  main:
    allow-bean-definition-overriding: true
  cloud:
    gateway:
      server:
        webflux:
          discovery:
            locator:
              enabled: true
              lower-case-service-id: true
          # 配置受信任代理(Spring Cloud 2025.0.0 新要求)
          trusted-proxies: "192\\.168\\..*|10\\..*|127\\.0\\.0\\.1"
          routes:
            # 用户服务路由
            - id: user-service
              uri: lb://user-service
              predicates:
                - Path=/api/users/**
              filters:
                - StripPrefix=1
            # 商品服务路由
            - id: product-service
              uri: lb://product-service
              predicates:
                - Path=/api/products/**
              filters:
                - StripPrefix=1
            # 订单服务路由
            - id: order-service
              uri: lb://order-service
              predicates:
                - Path=/api/orders/**
              filters:
                - StripPrefix=1
            # 支付服务路由
            - id: payment-service
              uri: lb://payment-service
              predicates:
                - Path=/api/payments/**
              filters:
                - StripPrefix=1
      # 全局 CORS 配置
      globals:
        cors-configurations:
          '[/**]':
            allowedOriginPatterns: "*"
            allowedMethods: "*"
            allowedHeaders: "*"
            allowCredentials: true
  # 配置Redis服务器地址和密码
  data:
    redis:
      host: 118.31.221.165
      port: 6379
      password: lihaozhe
      timeout: 2000ms
      lettuce:
        pool:
          max-active: 8
          max-idle: 8
          min-idle: 0
          max-wait: -1ms
        shutdown-timeout: 100ms

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    instance-id: ${spring.application.name}:${server.port}
    prefer-ip-address: true

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,gateway
  endpoint:
    health:
      show-details: always
    gateway:
      access: unrestricted

logging:
  level:
    org.springframework.cloud.gateway: DEBUG
    com.lihaozhe.apigateway: INFO
    reactor.netty.http.client: WARN
    org.springframework.data.redis: DEBUG

2. 其他服务配置调整

为了配合网关,我们需要调整其他服务的配置,确保它们可以通过网关正确路由。

用户服务配置调整
# user-service的application.properties
# 添加网关相关的头部信息支持
server.servlet.context-path=/

# 其他配置保持不变...
商品服务配置调整
# product-service的application.properties
# 添加网关相关的头部信息支持
server.servlet.context-path=/

# 其他配置保持不变...
订单服务配置调整
# order-service的application.properties
# 添加网关相关的头部信息支持
server.servlet.context-path=/

# 其他配置保持不变...
支付服务配置调整
# payment-service的application.properties
# 添加网关相关的头部信息支持
server.servlet.context-path=/

# 其他配置保持不变...

开发思路和过程

1. 网关设计原则:

  • 单一入口:所有外部请求都通过网关
  • 路由转发:根据规则将请求路由到对应服务
  • 横切关注点:在网关层处理认证、限流、监控等
  • 服务发现:与Eureka集成,动态发现服务实例

2. 网关核心概念:

  • 路由 (Route):定义转发规则,包括ID、目标URI、谓词和过滤器
  • 谓词 (Predicate):匹配请求的条件,如路径、方法、头部等
  • 过滤器 (Filter):处理请求和响应的逻辑,如添加头部、重试、限流等

3. 网关过滤器类型:

  • 全局过滤器 (Global Filter):对所有路由生效
  • 路由过滤器 (Route Filter):对特定路由生效

4. 常用网关功能:

  • 身份认证:验证请求的合法性
  • 动态路由:根据规则路由到不同服务
  • 请求限流:限制单位时间内的请求数量
  • 熔断降级:服务不可用时返回降级结果
  • 日志监控:记录请求日志和性能指标

运行测试

启动顺序:

  1. 启动Eureka Server (端口8761)
  2. 启动User Service (端口8081)
  3. 启动Product Service (端口8082)
  4. 启动Order Service (端口8083)
  5. 启动Payment Service (端口8086)
  6. 启动API Gateway (端口8080)

测试步骤:

# 1. 通过网关访问用户服务(无需认证)
curl http://localhost:8080/api/users/health

# 2. 通过网关访问商品服务
curl http://localhost:8080/api/products/1

# 3. 测试认证 - 不带token应该被拒绝
curl -X POST http://localhost:8080/api/orders \
  -H "Content-Type: application/json" \
  -H "X-Require-Auth: true" \
  -d '{"userId": 1, "productId": 1, "quantity": 1}'

# 4. 测试认证 - 带有效token
curl -X POST http://localhost:8080/api/orders \
  -H "Content-Type: application/json" \
  -H "X-Require-Auth: true" \
  -H "Authorization: Bearer valid_jwt_token_12345" \
  -d '{"userId": 1, "productId": 1, "quantity": 1}'

# 5. 测试支付服务(在工作时间内)
curl http://localhost:8080/api/payments/health

# 6. 查看网关状态信息
curl http://localhost:8080/gateway/status

# 7. 查看网关路由信息
curl http://localhost:8080/gateway/routes

# 8. 测试降级功能(停止某个服务后)
curl http://localhost:8080/api/users/1

# 9. 测试限流(快速连续调用)
for i in {1..15}; do
  curl http://localhost:8080/api/products/1 &
done
wait

# 10. 查看网关Actuator端点
curl http://localhost:8080/actuator/gateway/routes
curl http://localhost:8080/actuator/health

观察网关特性:

  • 所有请求都通过网关统一入口(端口8080)
  • 网关根据路径将请求路由到不同服务
  • 认证过滤器会检查请求头中的token
  • 日志过滤器记录请求处理时间和状态
  • 查看网关控制台日志,了解请求处理流程

这一章我们学习了Spring Cloud Gateway网关的使用,实现了统一的API入口和路由功能。

在下一章中,我们将学习Spring Cloud Config配置中心,实现配置的集中管理。

更多推荐