Gateway

一、为什么使用 Gateway(核心价值)

面临的原始问题:

  1. 硬编码问题:前端需要知道每个微服务的 IP 和端口

  2. 无负载均衡:无法在多个实例间分配请求

  3. 跨域问题:每个服务需单独处理

  4. 认证授权分散:每个服务重复实现登录校验

  5. 限流熔断复杂:需在每个服务集成

  6. 监控困难:请求分散,难以统一收集日志和指标

Gateway 带来的解决方案:

复制代码
前端/客户端
     |
  Gateway(统一入口)
     |
  ┌─────────────────────────────────┐
  │路由│过滤│限流│认证│监控│缓存│转换│
  └─────────────────────────────────┘
     |
  Nacos/注册中心
     |
┌────┬────┬────┬────┐
│服务1│服务2│服务3│...│
└────┴────┴────┴────┘

二、Gateway 核心概念补充

1. 三大核心概念

  • 路由(Route):转发的规则,包含ID、目标URI、断言、过滤器

  • 断言(Predicate):匹配条件(如路径、时间、Cookie等)

  • 过滤器(Filter):请求处理链(修改请求/响应)

2. 与 Zuul 对比

特性 Gateway Zuul 1.x
模型 异步非阻塞 同步阻塞
性能 较低
依赖 WebFlux Servlet
限流 原生支持 需集成
扩展性 一般

三、配置示例补充

1. 完整 application.yml 配置

复制代码
server:
  port: 8888

spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.61.132:8848
        namespace: dev
        group: DEFAULT_GROUP
    gateway:
      discovery:
        locator:
          enabled: true  # 开启从注册中心动态创建路由
      routes:
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
            - Method=GET,POST
            - After=2022-01-01T00:00:00.000+08:00
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10   # 每秒填充令牌数
                redis-rate-limiter.burstCapacity: 20   # 令牌桶容量
            - AddRequestHeader=X-Request-Gateway, spring-cloud-gateway
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - StripPrefix=1

2. 常见内置断言工厂

  • Path :路径匹配 /user/**

  • Method :请求方法 GET, POST

  • Header:请求头包含指定值

  • Cookie:Cookie 匹配

  • Query:查询参数匹配

  • Host:主机名匹配

  • Weight:权重路由

  • RemoteAddr:IP地址匹配

  • Time:时间相关(Before, After, Between)

3. 常见内置过滤器

  • 前缀处理PrefixPath, StripPrefix

  • 请求头AddRequestHeader, RemoveRequestHeader

  • 响应头AddResponseHeader

  • 重试Retry

  • 熔断CircuitBreaker

  • 限流RequestRateLimiter

  • 路径重写RewritePath


四、代码示例补充

1. 自定义断言工厂示例

复制代码
@Component
public class AgeRoutePredicateFactory extends AbstractRoutePredicateFactory<AgeRoutePredicateFactory.Config> {
    
    public AgeRoutePredicateFactory() {
        super(Config.class);
    }
    
    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return exchange -> {
            String ageStr = exchange.getRequest().getQueryParams().getFirst("age");
            if (ageStr == null) {
                return false;
            }
            int age = Integer.parseInt(ageStr);
            return age >= config.getMinAge() && age <= config.getMaxAge();
        };
    }
    
    @Data
    public static class Config {
        private int minAge;
        private int maxAge;
    }
    
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("minAge", "maxAge");
    }
}

2. 自定义过滤器工厂示例

复制代码
@Component
public class LogGatewayFilterFactory extends AbstractGatewayFilterFactory<LogGatewayFilterFactory.Config> {
    
    public LogGatewayFilterFactory() {
        super(Config.class);
    }
    
    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            if (config.isEnabled()) {
                ServerHttpRequest request = exchange.getRequest();
                log.info("Gateway Log: Path={}, Method={}, Params={}", 
                    request.getPath(), 
                    request.getMethod(),
                    request.getQueryParams());
            }
            return chain.filter(exchange);
        };
    }
    
    @Data
    public static class Config {
        private boolean enabled = true;
    }
}

3. 全局过滤器(认证示例)

复制代码
@Component
@Order(0)
public class AuthGlobalFilter implements GlobalFilter {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        
        // 1. 白名单路径放行
        if (isWhiteList(request.getPath().toString())) {
            return chain.filter(exchange);
        }
        
        // 2. 检查 token
        String token = request.getHeaders().getFirst("Authorization");
        if (StringUtils.isEmpty(token)) {
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        
        // 3. 验证 token
        if (!validateToken(token)) {
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.FORBIDDEN);
            return response.setComplete();
        }
        
        // 4. 添加用户信息到 header
        ServerHttpRequest newRequest = request.mutate()
            .header("X-User-Id", getUserIdFromToken(token))
            .build();
        
        return chain.filter(exchange.mutate().request(newRequest).build());
    }
    
    private boolean isWhiteList(String path) {
        return path.startsWith("/api/auth/login") 
            || path.startsWith("/api/public/");
    }
}

五、高级功能

1. 限流配置

复制代码
spring:
  redis:
    host: localhost
    port: 6379
  cloud:
    gateway:
      routes:
        - id: rate-limit-route
          uri: lb://user-service
          predicates:
            - Path=/api/**
          filters:
            - name: RequestRateLimiter
              args:
                key-resolver: "#{@userKeyResolver}"
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
                redis-rate-limiter.requestedTokens: 1

@Bean
public KeyResolver userKeyResolver() {
    return exchange -> Mono.just(
        exchange.getRequest().getQueryParams().getFirst("user")
    );
}

2. 熔断降级

复制代码
filters:
  - name: CircuitBreaker
    args:
      name: userServiceCB
      fallbackUri: forward:/fallback/user
  - name: Retry
    args:
      retries: 3
      statuses: BAD_GATEWAY, INTERNAL_SERVER_ERROR

六、最佳实践建议

  1. 生产配置

    复制代码
    # 开启 actuator 监控端点
    management:
      endpoints:
        web:
          exposure:
            include: health,info,gateway
  2. 统一异常处理

    复制代码
    @Component
    public class GlobalExceptionHandler implements ErrorWebExceptionHandler {
        // 统一处理 Gateway 异常
    }
  3. 链路追踪

    复制代码
    # 集成 Sleuth
    spring:
      sleuth:
        web:
          enabled: true
      zipkin:
        base-url: http://localhost:9411/
  4. CORS 配置

    复制代码
    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("*");
        config.addAllowedMethod("*");
        config.addAllowedHeader("*");
    
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
    
        return new CorsWebFilter(source);
    }

七、常见问题

1. 与 Web 模块冲突

复制代码
<!-- ❌ 错误:Gateway 不能引入 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- ✅ 正确:使用 WebFlux -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

2. 路由顺序问题

  • 路由按配置顺序匹配,先匹配先执行

  • 可以使用 order属性控制优先级

3. 性能调优

复制代码
spring:
  cloud:
    gateway:
      httpclient:
        connect-timeout: 1000
        response-timeout: 5s
        pool:
          max-connections: 1000
          acquire-timeout: 45000
相关推荐
武超杰3 小时前
Spring Cloud Gateway 从入门到实战
spring cloud·gateway
StackNoOverflow4 小时前
Spring Cloud Gateway 服务网关详解
gateway
tsyjjOvO5 小时前
服务网关 Gateway 从入门到精通
gateway
甜鲸鱼1 天前
JWT过滤器:从单体应用到微服务架构
微服务·架构·gateway·springcloud
notfound40431 天前
解决SpringCloudGateway用户请求超时导致日志未记录情况
java·spring boot·spring·gateway·springcloud
接着奏乐接着舞2 天前
gateway
gateway
一个public的class3 天前
前后端 + Nginx + Gateway + K8s 全链路架构图解
前端·后端·nginx·kubernetes·gateway
uNke DEPH4 天前
SpringCloud Gateway 集成 Sentinel 详解 及实现动态监听Nacos规则配置实时更新流控规则
spring cloud·gateway·sentinel
ERBU DISH5 天前
当遇到 502 错误(Bad Gateway)怎么办
gateway