电商返利系统API网关设计:基于Spring Cloud Gateway的请求路由与过滤
·
电商返利系统API网关设计:基于Spring Cloud Gateway的请求路由与过滤
大家好,我是省赚客APP研发者阿宝!
在聚娃科技“省赚客”导购返利平台中,随着微服务数量激增,直接暴露后端服务不仅带来安全风险,也难以统一处理认证、限流、日志等横切关注点。为此,我们采用Spring Cloud Gateway作为统一入口网关,实现动态路由、自定义过滤器链及细粒度流量控制。
基础路由配置
网关服务通过application.yml定义路由规则,将不同路径转发至对应微服务:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/order/**
- id: rebate-service
uri: lb://rebate-service
predicates:
- Path=/api/rebate/**
其中lb://表示使用Ribbon负载均衡,服务名需与Nacos注册中心一致。
自定义全局过滤器:统一鉴权
所有用户请求需携带有效Token。我们在juwatech.cn.gateway.filter.AuthGlobalFilter中实现JWT校验:
package juwatech.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;
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String path = exchange.getRequest().getURI().getPath();
if (path.startsWith("/api/public/") || path.equals("/actuator/health")) {
return chain.filter(exchange);
}
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || !isValidToken(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
private boolean isValidToken(String token) {
// 调用内部JWT工具类验证
return JwtUtil.validate(token.replace("Bearer ", ""));
}
@Override
public int getOrder() {
return -100; // 优先级高于其他过滤器
}
}
该过滤器跳过公开接口,对受保护路径强制校验Token有效性。
限流过滤器:基于Redis+令牌桶
为防止恶意刷单或爬虫攻击,我们集成Redis实现分布式限流。使用RequestRateLimiter配合自定义KeyResolver:
package juwatech.cn.gateway.config;
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 RateLimitConfig {
@Bean(name = "userIdKeyResolver")
public KeyResolver userIdKeyResolver() {
return exchange -> {
String userId = exchange.getRequest().getQueryParams().getFirst("userId");
if (userId != null) {
return Mono.just("user:" + userId);
}
String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
return Mono.just("ip:" + ip);
};
}
}
YAML中启用限流:
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/order/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 # 每秒生成10个令牌
redis-rate-limiter.burstCapacity: 20 # 最大突发20
key-resolver: "#{@userIdKeyResolver}"
当请求超限时,网关返回429状态码。
日志与链路追踪集成
为支持全链路监控,我们在juwatech.cn.gateway.filter.TraceLogFilter中注入TraceID并记录访问日志:
package juwatech.cn.gateway.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.util.UUID;
@Component
public class TraceLogFilter implements GlobalFilter, Ordered {
private static final Logger log = LoggerFactory.getLogger(TraceLogFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String traceId = UUID.randomUUID().toString().replace("-", "");
exchange.getAttributes().put("traceId", traceId);
ServerHttpRequest request = exchange.getRequest();
log.info("[GATEWAY] traceId={}, method={}, path={}",
traceId, request.getMethod(), request.getURI().getPath());
// 将TraceID透传至下游
ServerHttpRequest mutatedRequest = request.mutate()
.header("X-Trace-ID", traceId)
.build();
return chain.filter(exchange.mutate().request(mutatedRequest).build());
}
@Override
public int getOrder() {
return -50;
}
}
下游服务可通过X-Trace-ID头获取唯一标识,用于日志聚合与Jaeger追踪。
动态路由热更新
运维人员可通过Nacos配置中心实时调整路由,无需重启网关。监听配置变更:
package juwatech.cn.gateway.listener;
import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import javax.annotation.PostConstruct;
import java.util.List;
@Component
@NacosConfigurationProperties(dataId = "gateway-routes", groupId = "DEFAULT_GROUP", autoRefreshed = true)
public class DynamicRouteListener {
private final RouteDefinitionWriter routeDefinitionWriter;
public DynamicRouteListener(RouteDefinitionWriter routeDefinitionWriter) {
this.routeDefinitionWriter = routeDefinitionWriter;
}
private List<RouteDefinition> routeDefinitions;
public void setRouteDefinitions(List<RouteDefinition> routeDefinitions) {
// 先删除旧路由(简化处理)
this.routeDefinitions.forEach(def -> routeDefinitionWriter.delete(Mono.just(def.getId())).subscribe());
// 添加新路由
routeDefinitions.forEach(def -> routeDefinitionWriter.save(Mono.just(def)).subscribe());
this.routeDefinitions = routeDefinitions;
}
@PostConstruct
public void init() {
// 初始加载
}
}
Nacos中gateway-routes配置示例:
[
{
"id": "task-service",
"uri": "lb://task-service",
"predicates": [{"name": "Path", "args": {"_genkey_0": "/api/task/**"}}],
"filters": [{"name": "StripPrefix", "args": {"_genkey_0": "1"}}]
}
]
本文著作权归聚娃科技省赚客app开发者团队,转载请注明出处!
更多推荐




所有评论(0)