一、为什么选择 Gateway + Nacos
在微服务体系中选择网关,我们面临多种方案:
Nacos 则是阿里开源的服务发现与配置中心,相比 Eureka + Config,它有两大优势:
- 服务发现 + 配置中心合一,减少组件数量
- 支持 CP / AP 模式切换,适应不同场景
二、整体架构
``
客户端请求
│
▼
┌─────────────────────┐
│ Spring Cloud │
│ Gateway (LB) │ ← 路由、鉴权、限流、日志
└──────┬──────────────┘
│ 服务发现 (Nacos)
▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ user-service│ │ order-svc │ │ product-svc │
│ (2 nodes) │ │ (3 nodes) │ │ (2 nodes) │
└─────────────┘ └─────────────┘ └─────────────┘
`
三、Nacos 服务端部署
`yaml
`docker-compose.yml
version: '3.8'
services:
nacos:
image: nacos/nacos-server:v2.3.0
container_name: nacos
environment:
- MODE=standalone
- PREFER_HOST_MODE=hostname
- SPRING_DATASOURCE_PLATFORM=mysql
- MYSQL_SERVICE_HOST=mysql
- MYSQL_SERVICE_DB_NAME=nacos_config
- MYSQL_SERVICE_USER=root
- MYSQL_SERVICE_PASSWORD=root123
ports:
- "8848:8848"
- "9848:9848" # gRPC(服务端-客户端通信)
- "9849:9849" # gRPC(客户端-服务端通信)
restart: always
Nacos 2.x 使用 gRPC 通信,务必开放 9848/9849 端口,否则服务注册会失败!
四、Gateway 核心配置
依赖
`xml
`
路由配置
`yaml
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: production # 环境隔离
group: DEFAULT_GROUP
gateway: discovery: locator: enabled: true # 自动根据服务名创建路由 lower-case-service-id: true
routes: # 用户服务 - id: user-service uri: lb://user-service predicates: - Path=/api/users/** filters: - StripPrefix=1 - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 100 # 每秒令牌数 redis-rate-limiter.burstCapacity: 200 # 突发容量
# 订单服务 —— 灰度路由 - id: order-service-gray uri: lb://order-service predicates: - Path=/api/orders/** - Header=X-Version, v2 # Header 匹配走灰度 filters: - StripPrefix=1
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=1
`
五、全局过滤器
认证鉴权
`java
@Component
@Order(-1) // 优先级最高
public class AuthGlobalFilter implements GlobalFilter {
// 白名单路径
private static final Set
@Override
public Mono
// 白名单放行 if (isWhitelist(path)) { return chain.filter(exchange); }
String token = exchange.getRequest().getHeaders().getFirst("Authorization"); if (StringUtils.isBlank(token)) { return unauthorized(exchange, "缺少认证令牌"); }
return verifyToken(token)
.flatMap(userInfo -> {
// 将用户信息写入请求头,下游服务可直接使用
ServerHttpRequest newRequest = exchange.getRequest().mutate()
.header("X-User-Id", userInfo.getUserId())
.header("X-User-Name", userInfo.getUsername())
.header("X-User-Role", userInfo.getRole())
.build();
return chain.filter(exchange.mutate().request(newRequest).build());
})
.onErrorResume(e -> unauthorized(exchange, "令牌无效或已过期"));
}
}
`
全局异常处理
`java
@Configuration
public class GatewayExceptionConfig {
@Bean @Order(-2) public WebExceptionHandler globalExceptionHandler() { return (exchange, ex) -> { HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR; String message = "服务器内部错误";
if (ex instanceof ResponseStatusException rse) { status = HttpStatus.valueOf(rse.getStatusCode().value()); message = rse.getReason(); }
exchange.getResponse().setStatusCode(status); exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
byte[] body = String.format( "{"code":%d,"message":"%s"}", status.value(), message ).getBytes(StandardCharsets.UTF_8);
return exchange.getResponse()
.writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(body)));
};
}
}
`
六、Sentinel 熔断与降级
`yaml
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080 # Sentinel 控制台
datasource:
ds1:
nacos:
server-addr: localhost:8848
data-id: gateway-flow-rules
group-id: DEFAULT_GROUP
rule-type: gw-flow # 网关流控规则
`
Sentinel 控制台配置网关规则:
七、灰度发布
真实场景:新版本先放 10% 流量,观察无异常再全量发布。
`java
@Component
public class GrayLoadBalancer implements ReactorServiceInstanceLoadBalancer {
@Override
public Mono
return serviceInstanceListSupplier.get().next().map(instances -> {
List
if (candidates.isEmpty()) {
return new EmptyResponse();
}
// 随机选一个实例
int idx = ThreadLocalRandom.current().nextInt(candidates.size());
return new DefaultResponse(candidates.get(idx));
});
}
}
`
八、可观测性
日志 + 链路追踪
`yaml
`Micrometer + Brave (Zipkin)
management:
endpoints:
web:
exposure:
include: health,info,gateway,metrics
tracing:
sampling:
probability: 1.0
zipkin:
tracing:
endpoint: http://zipkin:9411/api/v2/spans
Gateway 自动为每个请求生成 TraceId,在响应头中返回 X-Trace-Id,排查问题时只需搜索一个 ID 就能还原完整调用链。
九、生产检查清单
十、总结
Spring Cloud Gateway + Nacos 的组合已经成为国内微服务网关的主流方案:
- 低运维成本:Nacos 替代 Eureka + Config + 部分 Sentinel 职责
- 高性能:响应式架构,单节点轻松支撑 10w+ QPS
- 灵活扩展:Filter 机制允许任意定制,灰度、限流、鉴权开箱即用
网关是微服务的"守门人"——守好这道门,后面的 99% 问题都能挡在外面。