SpringCloud 核心组件精讲:Spring Cloud Gateway 网关实战-路由配置 + 过滤器开发 + 限流鉴权(附场景配置模板)

前言

在微服务架构中,网关是整个系统的 "入口门面",负责请求路由、流量控制、权限校验、日志监控等核心功能。Spring Cloud Gateway 作为 Spring 官方推出的第二代网关(替代 Zuul),基于 Netty 非阻塞 IO 模型,具有性能高、功能强、易扩展等优势,完美适配微服务高并发场景。

本文将从 "原理→实战→进阶→生产落地" 全方位拆解 Spring Cloud Gateway,不仅覆盖路由配置、过滤器开发、限流鉴权等核心场景,还提供可直接复制的配置模板和避坑指南。内容兼顾新手入门与老手优化,既有基础操作的 step-by-step 教程,也有底层原理和生产级优化技巧,助力你快速掌握网关实战能力。

1. 为什么选择 Spring Cloud Gateway?核心优势与架构原理

1.1 核心优势(对比 Zuul)

  • 性能优异:基于 Netty 响应式编程,非阻塞 IO 模型,吞吐量是 Zuul 1.x 的 3 倍以上
  • 功能强大:原生支持路由、过滤、限流、熔断、重试等核心功能,无需额外集成
  • 易扩展:基于 Spring 生态,支持自定义过滤器、路由断言,适配各种业务场景
  • 无缝整合:与 Spring Cloud Alibaba、Nacos、Sentinel 等组件完美兼容
  • 支持 WebSocket:原生支持 WebSocket 协议,适合实时通信场景(如消息推送)

1.2 核心架构原理

Spring Cloud Gateway 的核心是 "路由(Route)+ 断言(Predicate)+ 过滤器(Filter)" 的三元组模型:

  • 路由(Route):网关的基本单元,包含 ID、目标 URI、断言集合、过滤器集合
  • 断言(Predicate):路由匹配规则,如路径、方法、参数、Header 等,满足条件则转发
  • 过滤器(Filter):请求 / 响应的拦截器,分全局过滤器(对所有路由生效)和局部过滤器(对指定路由生效)

1.3 核心流程拆解

  1. 客户端发送请求到 Gateway
  2. 网关根据断言(Predicate)匹配对应的路由
  3. 请求经过 "前置过滤器链" 处理(如鉴权、日志、限流)
  4. 网关将请求转发到目标微服务
  5. 微服务返回响应,经过 "后置过滤器链" 处理(如响应改写、数据加密)
  6. 网关将最终响应返回给客户端

2. 快速上手:3 步搭建基础网关(附完整配置)

2.1 环境准备

  • 技术栈:SpringBoot 2.7.x + SpringCloud 2021.0.4 + SpringCloud Gateway 3.1.4
  • 注册中心:Nacos 2.2.3(服务发现)
  • 微服务:已部署user-serviceorder-service(作为路由目标服务)

2.2 步骤 1:引入核心依赖

XML 复制代码
<!-- Spring Cloud Gateway核心依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Nacos服务发现依赖(网关需从注册中心获取服务列表) -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringBoot Actuator(监控用,可选) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

注意:Gateway 基于响应式编程,不能引入 spring-boot-starter-web 依赖(会导致 Netty 冲突)

2.3 步骤 2:配置 application.yml

bash 复制代码
spring:
  application:
    name: gateway-service # 网关服务名
  cloud:
    # Nacos配置
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 # Nacos地址
    # Gateway配置
    gateway:
      # 路由配置(静态路由)
      routes:
        # 路由1:转发到用户服务
        - id: user-service-route # 路由唯一ID(自定义)
          uri: lb://user-service # 目标服务名(lb=loadbalance,负载均衡)
          predicates:
            - Path=/api/user/** # 路径断言:匹配/api/user/开头的请求
          filters:
            - StripPrefix=1 # 过滤规则:去除路径前缀1级(/api/user/get → /user/get)
        # 路由2:转发到订单服务
        - id: order-service-route
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          filters:
            - StripPrefix=1
  # 端口配置(网关端口)
server:
  port: 8080

# 监控配置(暴露路由信息)
management:
  endpoints:
    web:
      exposure:
        include: gateway,health,info # 暴露gateway端点
  endpoint:
    gateway:
      enabled: true # 启用网关监控端点

2.4 步骤 3:编写启动类

java 复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient // 开启服务发现(Nacos)
public class GatewayServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayServiceApplication.class, args);
    }
}

2.5 测试验证

  1. 启动 Nacos、user-serviceorder-servicegateway-service
  2. 访问网关地址:http://localhost:8080/api/user/get/1 → 转发到user-service/user/get/1接口
  3. 访问http://localhost:8080/api/order/create → 转发到order-service/order/create接口
  4. 访问监控端点:http://localhost:8080/actuator/gateway/routes → 查看所有路由配置

3. 路由配置实战:静态路由 + 动态路由(Nacos 适配)

路由是 Gateway 的核心,分为静态路由(配置文件)和动态路由(配置中心),动态路由支持配置热更新,无需重启网关。

3.1 静态路由:多种匹配规则(Predicate)

除了路径匹配,Gateway 支持多种断言规则,可组合使用:

bash 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: multi-predicate-route
          uri: lb://user-service
          predicates:
            # 1. 路径匹配:/api/user/** 或 /api/member/**
            - Path=/api/user/**,/api/member/**
            # 2. 请求方法匹配:GET/POST
            - Method=GET,POST
            # 3. 参数匹配:必须包含userId参数(值可为任意)
            - Query=userId
            # 4. Header匹配:必须包含Authorization头
            - Header=Authorization
            # 5. 时间匹配:2024-01-01 00:00:00后生效
            - After=2024-01-01T00:00:00+08:00[Asia/Shanghai]
          filters:
            - StripPrefix=1

3.2 动态路由:基于 Nacos 实现热更新

静态路由修改后需重启网关,生产环境推荐使用动态路由,通过 Nacos 配置中心实现配置实时刷新。

3.2.1 引入 Nacos 配置依赖
XML 复制代码
<!-- Nacos配置中心依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
3.2.2 配置 bootstrap.yml(优先级高于 application.yml)
bash 复制代码
spring:
  application:
    name: gateway-service
  cloud:
    nacos:
      # 配置中心
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yaml # 配置文件格式
        group: DEFAULT_GROUP # 配置分组
      # 服务发现
      discovery:
        server-addr: 127.0.0.1:8848
3.2.3 在 Nacos 中创建配置
  1. 登录 Nacos 控制台 → 配置管理 → 配置列表 → 新建
  2. 配置信息:
    • 数据 ID:gateway-service.yaml(服务名 + 文件格式)
    • 分组:DEFAULT_GROUP
    • 配置内容(路由配置):
bash 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: dynamic-user-route
          uri: lb://user-service
          predicates:
            - Path=/dynamic/user/**
          filters:
            - StripPrefix=1
        - id: dynamic-order-route
          uri: lb://order-service
          predicates:
            - Path=/dynamic/order/**
          filters:
            - StripPrefix=1
3.2.4 编写动态路由配置类
java 复制代码
import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;

@Configuration
public class DynamicRouteConfig {

    // 路由定义写入器(用于动态更新路由)
    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    // Nacos配置属性
    @Autowired
    private NacosConfigProperties nacosConfigProperties;

    // 配置ID(与Nacos中一致)
    private static final String DATA_ID = "gateway-service.yaml";
    // 配置分组
    private static final String GROUP = "DEFAULT_GROUP";

    // 项目启动时加载路由,且监听配置变化
    @PostConstruct
    public void dynamicRouteByNacos() throws NacosException {
        // 1. 初始化Nacos配置服务
        Properties properties = new Properties();
        properties.put("serverAddr", nacosConfigProperties.getServerAddr());
        ConfigService configService = NacosFactory.createConfigService(properties);

        // 2. 首次加载配置
        String configInfo = configService.getConfig(DATA_ID, GROUP, 5000);
        updateRoute(configInfo);

        // 3. 监听配置变化(热更新)
        configService.addListener(DATA_ID, GROUP, new Listener() {
            @Override
            public Executor getExecutor() {
                return null;
            }

            @Override
            public void receiveConfigInfo(String configInfo) {
                // 配置变化时更新路由
                updateRoute(configInfo);
            }
        });
    }

    // 解析配置并更新路由
    private void updateRoute(String configInfo) {
        // 解析Nacos配置中的routes节点
        GatewayConfig gatewayConfig = JSON.parseObject(configInfo, GatewayConfig.class);
        List<RouteDefinition> routeDefinitions = gatewayConfig.getSpring().getCloud().getGateway().getRoutes();

        // 先删除所有旧路由
        routeDefinitions.forEach(route -> {
            routeDefinitionWriter.delete(Mono.just(route.getId())).subscribe();
        });

        // 再添加新路由
        routeDefinitions.forEach(route -> {
            routeDefinitionWriter.save(Mono.just(route)).subscribe();
        });
    }

    // 自定义配置类(对应Nacos中的配置结构)
    static class GatewayConfig {
        private Spring spring;

        // getter/setter
        public Spring getSpring() { return spring; }
        public void setSpring(Spring spring) { this.spring = spring; }

        static class Spring {
            private Cloud cloud;

            // getter/setter
            public Cloud getCloud() { return cloud; }
            public void setCloud(Cloud cloud) { this.cloud = cloud; }
        }

        static class Cloud {
            private Gateway gateway;

            // getter/setter
            public Gateway getGateway() { return gateway; }
            public void setGateway(Gateway gateway) { this.gateway = gateway; }
        }

        static class Gateway {
            private List<RouteDefinition> routes;

            // getter/setter
            public List<RouteDefinition> getRoutes() { return routes; }
            public void setRoutes(List<RouteDefinition> routes) { this.routes = routes; }
        }
    }
}
3.2.5 测试动态路由
  1. 修改 Nacos 中的路由配置(如添加新路由、修改路径匹配规则)
  2. 无需重启网关,访问新路由地址 → 直接生效
  3. 访问http://localhost:8080/actuator/gateway/routes → 查看更新后的路由

4. 过滤器开发:全局过滤器 + 局部过滤器(含实战案例)

Gateway 的过滤器分为全局过滤器 (对所有路由生效)和局部过滤器(仅对指定路由生效),核心作用是对请求 / 响应进行拦截增强。

4.1 过滤器执行顺序

  • 前置过滤器(Pre):请求转发前执行(如鉴权、日志、参数改写)
  • 后置过滤器(Post):响应返回前执行(如响应加密、数据格式化)

4.2 全局过滤器实战:3 个高频场景

4.2.1 场景 1:全局日志打印(记录请求响应)
java 复制代码
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;

@Configuration
public class GlobalLogFilterConfig {

    // Order值越小,执行优先级越高
    @Bean
    @Order(-100)
    public GlobalFilter logFilter() {
        return (exchange, chain) -> {
            // 1. 前置处理:记录请求信息
            String path = exchange.getRequest().getPath().value();
            String method = exchange.getRequest().getMethod().name();
            String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
            System.out.printf("[%s] 收到请求:IP=%s, 方法=%s, 路径=%s%n",
                    LocalDateTime.now(), ip, method, path);

            // 2. 继续执行后续过滤器
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                // 3. 后置处理:记录响应信息
                int statusCode = exchange.getResponse().getStatusCode().value();
                System.out.printf("[%s] 响应结果:状态码=%s, 路径=%s%n",
                        LocalDateTime.now(), statusCode, path);
            }));
        };
    }
}
4.2.2 场景 2:全局跨域处理(解决前后端跨域)
java 复制代码
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import reactor.core.publisher.Mono;

@Configuration
public class GlobalCorsFilterConfig {

    @Bean
    @Order(-101)
    public GlobalFilter corsFilter() {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();

            // 允许所有源跨域
            response.getHeaders().add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
            // 允许的请求头
            response.getHeaders().add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "*");
            // 允许的请求方法
            response.getHeaders().add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET,POST,PUT,DELETE,OPTIONS");
            // 预检请求缓存时间
            response.getHeaders().add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "3600");

            // 处理OPTIONS预检请求
            if (request.getMethod() == HttpMethod.OPTIONS) {
                response.setStatusCode(HttpStatus.OK);
                return Mono.empty();
            }

            return chain.filter(exchange);
        };
    }
}
4.2.3 场景 3:全局鉴权过滤器(JWT Token 验证)
java 复制代码
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Mono;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

@Configuration
public class GlobalAuthFilterConfig {

    // 放行的白名单(无需鉴权的路径)
    private static final List<String> WHITE_LIST = new ArrayList<>();

    static {
        WHITE_LIST.add("/api/user/login");
        WHITE_LIST.add("/api/user/register");
        WHITE_LIST.add("/actuator/**");
    }

    // JWT密钥(生产环境需配置在Nacos,避免硬编码)
    private static final String JWT_SECRET = "your-secret-key-32bytes-long-123456";
    private final SecretKey secretKey = Keys.hmacShaKeyFor(JWT_SECRET.getBytes(StandardCharsets.UTF_8));

    @Bean
    @Order(-99) // 优先级高于日志过滤器
    public GlobalFilter authFilter() {
        return (exchange, chain) -> {
            String path = exchange.getRequest().getPath().value();

            // 1. 白名单路径直接放行
            if (WHITE_LIST.stream().anyMatch(path::startsWith)) {
                return chain.filter(exchange);
            }

            // 2. 从Header获取Token
            String token = exchange.getRequest().getHeaders().getFirst("Authorization");
            if (!StringUtils.hasText(token) || !token.startsWith("Bearer ")) {
                // Token不存在,返回401
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }

            // 3. 验证Token有效性
            token = token.substring(7); // 去除Bearer前缀
            try {
                Claims claims = Jwts.parserBuilder()
                        .setSigningKey(secretKey)
                        .build()
                        .parseClaimsJws(token)
                        .getBody();

                // 4. Token有效,将用户信息存入请求头(传递给微服务)
                String userId = claims.get("userId", String.class);
                ServerHttpRequest request = exchange.getRequest().mutate()
                        .header("X-User-Id", userId)
                        .build();
                return chain.filter(exchange.mutate().request(request).build());

            } catch (Exception e) {
                // Token无效/过期,返回401
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }
        };
    }
}

4.3 局部过滤器实战:请求改写与响应处理

局部过滤器仅对指定路由生效,需实现GatewayFilter接口:

java 复制代码
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

// 局部过滤器:给请求添加固定参数
@Component
public class AddParamGatewayFilterFactory extends AbstractGatewayFilterFactory<AddParamGatewayFilterFactory.Config> {

    // 配置类(接收过滤器参数)
    public static class Config {
        private String paramName; // 参数名
        private String paramValue; // 参数值

        // getter/setter
        public String getParamName() { return paramName; }
        public void setParamName(String paramName) { this.paramName = paramName; }
        public String getParamValue() { return paramValue; }
        public void setParamValue(String paramValue) { this.paramValue = paramValue; }
    }

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

    // 配置参数的默认顺序(用于yml配置)
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("paramName", "paramValue");
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            // 给请求添加固定参数
            ServerHttpRequest request = exchange.getRequest().mutate()
                    .queryParam(config.getParamName(), config.getParamValue())
                    .build();
            return chain.filter(exchange.mutate().request(request).build());
        };
    }
}
局部过滤器使用(在路由中配置)
bash 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: user-service-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - StripPrefix=1
            # 局部过滤器:添加paramName=version,paramValue=v1.0
            - AddParam=version,v1.0

5. 限流鉴权核心实现:基于 Redis 的限流 + JWT 鉴权

5.1 限流实现:基于 Redis 的令牌桶算法

Gateway 自带限流过滤器RequestRateLimiter,结合 Redis 可实现分布式限流(支持 IP、用户 ID、接口等维度)。

5.1.1 引入 Redis 依赖
XML 复制代码
<!-- Redis依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
5.1.2 配置 Redis 与限流规则
bash 复制代码
spring:
  redis:
    host: 127.0.0.1
    port: 6379
    password: # 无密码留空
    database: 0
  cloud:
    gateway:
      routes:
        - id: user-service-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - StripPrefix=1
            # 限流配置:基于IP,10秒内允许5次请求
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 0.5 # 令牌桶填充速率(每秒0.5个)
                redis-rate-limiter.burstCapacity: 5 # 令牌桶最大容量(5个)
                key-resolver: "#{@ipKeyResolver}" # 限流Key解析器(IP维度)
5.1.3 自定义限流 Key 解析器
java 复制代码
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;

@Configuration
public class RateLimitKeyResolverConfig {

    // 1. 基于IP的限流Key解析器
    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> {
            // 获取客户端IP
            String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
            return Mono.just(ip);
        };
    }

    // 2. 基于用户ID的限流Key解析器(需配合鉴权过滤器)
    @Bean
    public KeyResolver userIdKeyResolver() {
        return exchange -> {
            // 从请求头获取用户ID(鉴权过滤器传递)
            String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
            // 未登录用户用IP替代
            return Mono.just(userId != null ? userId : ipKeyResolver().resolve(exchange).block());
        };
    }

    // 3. 基于接口路径的限流Key解析器
    @Bean
    public KeyResolver pathKeyResolver() {
        return exchange -> {
            String path = exchange.getRequest().getPath().value();
            return Mono.just(path);
        };
    }
}
5.1.4 限流效果测试
  1. 10 秒内多次访问http://localhost:8080/api/user/get/1
  2. 超过 5 次后,网关返回 429 Too Many Requests
  3. Redis 中会生成限流相关 Key(如request_rate_limiter.{IP}.timestamp

5.2 鉴权完整流程:JWT + 权限校验

5.2.1 JWT 生成(用户登录接口)

user-service中实现登录接口,生成 JWT Token:

java 复制代码
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;

@RestController
@RequestMapping("/user")
public class UserController {

    private static final String JWT_SECRET = "your-secret-key-32bytes-long-123456";
    private final SecretKey secretKey = Keys.hmacShaKeyFor(JWT_SECRET.getBytes(StandardCharsets.UTF_8));
    private static final long EXPIRATION = 3600000; // Token有效期1小时

    @PostMapping("/login")
    public String login(@RequestParam String username, @RequestParam String password) {
        // 1. 校验用户名密码(实际场景从数据库查询)
        if ("admin".equals(username) && "123456".equals(password)) {
            // 2. 生成JWT Token
            String token = Jwts.builder()
                    .setSubject(username) // 用户名
                    .claim("userId", "1001") // 自定义字段:用户ID
                    .claim("role", "ADMIN") // 自定义字段:角色
                    .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)) // 过期时间
                    .signWith(secretKey) // 签名
                    .compact();
            return "Bearer " + token;
        }
        return "登录失败";
    }
}
5.2.2 权限校验(基于角色)

在全局鉴权过滤器中扩展角色校验:

java 复制代码
// 在GlobalAuthFilterConfig的authFilter中添加
String role = claims.get("role", String.class);
// 示例:只有ADMIN角色能访问/admin路径
if (path.startsWith("/api/admin") && !"ADMIN".equals(role)) {
    exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN); // 403
    return exchange.getResponse().setComplete();
}

6. 生产环境优化:性能调优 + 熔断降级 + 监控告警

6.1 性能调优配置

bash 复制代码
spring:
  cloud:
    gateway:
      httpclient:
        pool:
          max-idle-time: 60000 # 连接池最大空闲时间(毫秒)
          max-connections: 1000 # 每个路由的最大连接数
          max-pending-connections: 500 # 最大等待连接数
        connect-timeout: 3000 # 连接超时时间(毫秒)
        response-timeout: 5000 # 响应超时时间(毫秒)
      threads:
        worker: 200 # 工作线程数(建议为CPU核心数*2)
server:
  port: 8080
  netty:
    connection-timeout: 2000 # Netty连接超时时间
    threads:
      worker: 200 # Netty工作线程数

6.2 熔断降级(整合 Sentinel)

避免下游服务故障导致网关阻塞,通过 Sentinel 实现熔断降级:

XML 复制代码
<!-- Sentinel依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
bash 复制代码
spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080 # Sentinel控制台地址
      scg:
        fallback:
          mode: response # 降级模式:返回固定响应
          response-status: 503 # 降级状态码
          response-body: '{"code":503,"message":"服务繁忙,请稍后再试"}' # 降级响应体

6.3 监控告警

  • 暴露 Actuator 端点,结合 Prometheus+Grafana 监控路由命中率、响应时间、限流次数
  • 配置 Sentinel 告警规则,服务异常时通过邮件 / 钉钉通知运维

7. 高频场景配置模板(直接复制使用)

模板 1:静态路由完整配置

bash 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: user-service-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
            - Method=GET,POST
            - Header=Authorization
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1
                redis-rate-limiter.burstCapacity: 10
                key-resolver: "#{@ipKeyResolver}"

模板 2:跨域配置(全局)

bash 复制代码
spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowed-origins: "*"
            allowed-methods: "*"
            allowed-headers: "*"
            allow-credentials: true
            max-age: 3600

模板 3:Redis 限流配置(基于用户 ID)

bash 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: order-service-route
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 2
                redis-rate-limiter.burstCapacity: 20
                key-resolver: "#{@userIdKeyResolver}"

模板 4:熔断降级配置(Sentinel)

bash 复制代码
spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080
      scg:
        fallback:
          mode: redirect # 降级模式:重定向到错误页面
          redirect: /error.html # 降级跳转页面

8. 实战避坑指南(10 个实测踩坑总结)

  1. 依赖冲突 :引入spring-boot-starter-web导致 Netty 冲突,需删除该依赖
  2. 跨域配置失效:同时配置了全局 CorsFilter 和 globalcors,优先级冲突,选择一种即可
  3. 动态路由不生效:Nacos 配置的 dataId 与 bootstrap.yml 不一致,或路由 ID 重复
  4. 限流不生效 :未引入spring-boot-starter-data-redis-reactive依赖,或 Redis 连接失败
  5. Token 传递丢失 :多线程环境下RequestContextHolder获取不到请求,需手动传递 ThreadLocal
  6. 路由匹配优先级:路由配置顺序即匹配优先级,精确路径路由应放在前面
  7. StripPrefix 失效 :路径匹配规则与 StripPrefix 级数不匹配(如/api/user/**对应 StripPrefix=1)
  8. 响应超时配置无效:需同时配置 Gateway 的 httpclient.response-timeout 和微服务的超时时间
  9. Sentinel 熔断不生效 :未引入spring-cloud-alibaba-sentinel-gateway依赖
  10. 日志打印乱码 :Netty 默认编码为 ISO-8859-1,需配置 JVM 参数-Dfile.encoding=UTF-8

9. 面试高频考点梳理

  1. Spring Cloud Gateway 的核心组件?(路由、断言、过滤器)
  2. Gateway 与 Zuul 的区别?(性能、模型、功能支持)
  3. Gateway 的过滤器执行顺序?(全局→局部,前置→后置,Order 值越小优先级越高)
  4. 如何实现动态路由?(基于 Nacos 配置中心 + RouteDefinitionWriter)
  5. Gateway 的限流算法是什么?(令牌桶算法,基于 Redis 实现分布式限流)
  6. 如何解决 Gateway 的跨域问题?(全局 CorsFilter 或 globalcors 配置)
  7. Gateway 如何实现鉴权?(全局过滤器 + JWT Token 验证)
  8. Gateway 的性能优化手段?(连接池配置、线程数调整、压缩、缓存)

10. 总结与展望

Spring Cloud Gateway 作为微服务架构的核心网关,凭借其高性能、强扩展性、丰富的功能,成为企业级微服务项目的首选。本文从基础搭建到生产落地,覆盖了路由、过滤、限流、鉴权等核心场景,提供的配置模板和避坑指南可直接应用于实际项目。

后续可进一步探索 Gateway 的高级特性,如:

  • 灰度发布(基于权重路由)
  • 分布式链路追踪(整合 SkyWalking/Zipkin)
  • 网关层数据脱敏
  • 自定义路由断言工厂

如果在实战中遇到具体问题,欢迎在评论区留言讨论,一起交流进步!

相关推荐
无知就要求知2 小时前
golang实现ftp功能简单又实用
java·前端·golang
海南java第二人2 小时前
深入剖析AQS:Java并发编程的核心基石与底层实现原理
java
趁月色小酌***2 小时前
JAVA 知识点总结3
java·开发语言·python
阿拉斯攀登2 小时前
设计模式:Spring MVC 中命令模式的核心映射与设计逻辑
spring·设计模式·mvc·命令模式
fufu03112 小时前
Linux环境下的C语言编程(五十二)
java·linux·c语言
BD_Marathon2 小时前
Spring是什么
java·后端·spring
我命由我123452 小时前
Android 消息机制 - Looper(Looper 静态方法、Looper 静态方法注意事项、Looper 实例方法、Looper 实例方法注意事项)
android·java·android studio·安卓·android jetpack·android-studio·android runtime
月明长歌2 小时前
【码道初阶】Leetcode138:随机链表的复制:用 HashMap 做深拷贝的标准解法
java·数据结构·算法·leetcode·链表·哈希算法
.简.简.单.单.2 小时前
Design Patterns In Modern C++ 中文版翻译 第八章 组合
java·c++·设计模式