没有网关的日子
服务拆完,App 端直连十几个服务:鉴权逻辑每个服务抄一遍,证书在十几台机器上轮换,接口改个路径,App 的老版本还在往旧地址打。入口不收敛,横切逻辑就无处安放——鉴权、限流、日志、协议适配,每一件都不复杂,散在十几个服务里就是灾难。网关把这些横切能力收到统一入口,服务只管业务。
网关的职责边界
网关该做的:路由转发——对外一个域名,对内一张路由表;统一鉴权——Token 校验与用户上下文透传;入口限流与黑名单;统一日志与指标;协议适配。网关不该做的:业务逻辑。一旦鉴权之外开始长业务分支——"VIP 用户走不同路由"这类规则蔓延成业务编排——网关就变成了新的单体,发布频率直追业务服务,横切能力改一次全站等它。
| 该放网关 | 不该放网关 |
|---|---|
| 路由、鉴权、限流、黑名单 | 业务规则编排 |
| 统一日志、指标、链路入口 | 数据加工与聚合 |
| 协议适配、灰度分流 | 需要频繁发版的业务逻辑 |
Spring Cloud Gateway 的三件套
核心模型三样:Route(一条路由规则)、Predicate(断言——决定请求匹配哪条路由:路径、Header、参数、时间)、Filter(过滤器——请求与响应两端的处理链)。断言决定谁处理,过滤器决定怎么处理,鉴权、改头、限流都是过滤器。
spring:
cloud:
gateway:
routes:
- id: order-route
uri: lb://order-service # lb:// 走注册中心做负载均衡
predicates:
- Path=/api/order/**
filters:
- StripPrefix=1 # 转发前剥掉一级路径
- id: inventory-route
uri: lb://inventory-service
predicates:
- Path=/api/stock/**
filters:
- name: RequestRateLimiter # 网关层限流
args:
redis-rate-limiter.replenishRate: 500统一鉴权怎么放
主流做法:网关统一校验 JWT——签名、过期时间、黑名单;校验通过把用户 ID 等关键信息放进请求头透传给下游,下游只信网关头(配合内网隔离防伪造),不再各自解析 Token。白名单(登录、健康检查)放过滤器最前面短路。两个细节:校验失败要返回 401 而不是 404,语义要清楚;透传的 Header 名加统一前缀(如 X-User-Id),避免和业务参数撞名。
@Component
public class AuthFilter implements GlobalFilter, Ordered {
public Mono<Void> filter(ServerWebExchange ex, GatewayFilterChain chain) {
String path = ex.getRequest().getPath().value();
if (WHITE_LIST.stream().anyMatch(path::startsWith)) {
return chain.filter(ex); // 白名单短路
}
String token = ex.getRequest().getHeaders().getFirst("Authorization");
if (token == null || !jwtVerifier.check(token)) {
ex.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return ex.getResponse().setComplete(); // 401,语义清楚
}
// 解析用户并透传给下游
ServerHttpRequest req = ex.getRequest().mutate()
.header("X-User-Id", jwtVerifier.userId(token)).build();
return chain.filter(ex.mutate().request(req).build());
}
public int getOrder() { return -100; } // 尽量早执行
}网关自己的可用性
网关是全站单点风险,自身要做三件事:无状态水平扩展——前面挂 LB,随时加减实例;自身也有限流——入口的总量阀门,别让网关先被打死;监控告警独立——网关的 RT 与错误率异常往往代表全站问题,要最先看见。下一篇讲网关的两个高频实战:动态路由与灰度发布。
评论 (0)