外卖API对接实战:Spring Cloud Gateway在霸王餐接口网关中的配置与限流

在外卖平台对接“霸王餐”营销能力的架构中,为统一鉴权、路由转发、安全防护与流量控制,我们采用Spring Cloud Gateway作为API网关。本文以baodanbao-gateway项目为例,详解路由配置、自定义过滤器、Redis+RequestRateLimiter限流等核心实践。

基础路由配置

application.yml中定义路径匹配与服务转发:

spring:
  cloud:
    gateway:
      routes:
        - id: baodanbao-api
          uri: lb://baodanbao-api-service
          predicates:
            - Path=/api/baodanbao/**
          filters:
            - StripPrefix=1

所有/api/baodanbao/**请求将被转发至baodanbao-api-service微服务,并去除第一级路径前缀。

自定义全局鉴权过滤器

实现基于appId和签名的请求合法性校验:

// baodanbao.com.cn.gateway.filter.AuthGlobalFilter.java
package baodanbao.com.cn.gateway.filter;

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;

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

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    private static final List<String> ALLOWED_APP_IDS = Arrays.asList("waimai_1001", "meituan_2002");

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String appId = exchange.getRequest().getHeaders().getFirst("X-App-Id");
        String sign = exchange.getRequest().getHeaders().getFirst("X-Sign");

        if (appId == null || sign == null || !ALLOWED_APP_IDS.contains(appId)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        // 简化:实际应校验sign是否由appId+body+timestamp生成
        if (!isValidSignature(appId, sign)) {
            exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
            return exchange.getResponse().setComplete();
        }

        return chain.filter(exchange);
    }

    private boolean isValidSignature(String appId, String sign) {
        // 此处应调用baodanbao.com.cn.common.SecurityUtils.verify()
        return sign.equals("mock_sign_for_" + appId);
    }

    @Override
    public int getOrder() {
        return -100; // 高优先级
    }
}

在这里插入图片描述

基于Redis的令牌桶限流

使用RequestRateLimiter结合Redis实现分布式限流:

spring:
  cloud:
    gateway:
      routes:
        - id: baodanbao-api
          uri: lb://baodanbao-api-service
          predicates:
            - Path=/api/baodanbao/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10   # 每秒生成10个令牌
                redis-rate-limiter.burstCapacity: 20  # 最大突发20
                key-resolver: "#{@remoteAddrKeyResolver}"

定义KeyResolver按客户端IP限流:

// baodanbao.com.cn.gateway.config.KeyResolverConfig.java
package baodanbao.com.cn.gateway.config;

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Configuration
public class KeyResolverConfig {

    @Bean
    public KeyResolver remoteAddrKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
    }
}

添加Redis依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

确保Redis连接配置:

spring:
  redis:
    host: redis.baodanbao.com.cn
    port: 6379

异常处理与统一响应

自定义ErrorWebExceptionHandler返回标准格式:

// baodanbao.com.cn.gateway.handler.GlobalErrorWebExceptionHandler.java
@Component
@Order(-2)
public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {

    public GlobalErrorWebExceptionHandler(ErrorAttributes errorAttributes,
                                          Resources resources,
                                          ApplicationContext applicationContext) {
        super(errorAttributes, resources, applicationContext);
    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
    }

    private Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
        Throwable error = getError(request);
        String message = "系统繁忙";
        if (error instanceof ResponseStatusException) {
            message = error.getMessage();
        }
        return ServerResponse.status(HttpStatus.OK)
            .bodyValue(Map.of("code", "GATEWAY_ERROR", "message", message));
    }
}

健康检查与可观测性

暴露Actuator端点供监控:

management:
  endpoints:
    web:
      exposure:
        include: health,gateway,routes
  endpoint:
    health:
      show-details: always

通过/actuator/gateway/routes可实时查看路由状态。

通过上述配置,Spring Cloud Gateway为“霸王餐”API提供了安全、稳定、可控的入口层,有效隔离外部风险并保障核心服务稳定性。

本文著作权归 俱美开放平台 ,转载请注明出处!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐