Spring Cloud Gateway 微服务统一入口实战
为什么需要 API 网关
在微服务架构中,我们通常通过注册中心(如 Nacos、Eureka)解决服务发现问题,用负载均衡器处理流量分发。但随之而来的一个痛点是:所有微服务的接口都直接暴露在外,外部客户端可以直接访问任意服务。
为了保证安全性,每个微服务内部都需要实现权限校验逻辑。一旦业务拆分,原本单体应用中的单一校验点变成了多个应用的重复代码。当需要修改鉴权规则时,开发人员得逐个修改所有服务,维护成本极高。
这就好比一家公司,以前只有一个员工负责接待和核实身份;后来部门多了,每个部门都要自己核实访客身份,效率低且流程繁琐。设立一个统一的前台(API 网关),由前台先核实身份,通过后放行到各部门,是更优的解决方案。
什么是 API 网关
API 网关是后端服务的唯一入口,类似于设计模式中的门面模式(Facade)。它对外提供统一的调度与过滤能力,核心功能包括:
- 权限控制:作为入口拦截非法请求,统一进行鉴权。
- 动态路由:根据规则将请求转发到对应的微服务,不处理具体业务。
- 负载均衡:当目标服务有多个实例时,自动分配流量。
- 限流熔断:控制进入后端的流量,防止服务压力过大。
常见网关实现
业界成熟的网关方案不少,比如 Nginx、Kong、Zuul 等。在 Spring Cloud 生态中,主要对比的是 Zuul 和 Spring Cloud Gateway。
- Zuul:Netflix 开源组件,早期 Spring Cloud 推荐方案。但在 2018 年后 Netflix 宣布部分组件进入维护状态,不再开发新特性,性能方面基于 Servlet 阻塞模型也略显吃力。
- Spring Cloud Gateway:Spring Cloud 全新项目,基于 Spring Boot 和 WebFlux 响应式栈开发,旨在替代 Zuul。官方测试显示其 RPS(每秒请求数)约为 Zuul 的 1.6 倍,更适合高并发场景。
快速上手
创建项目与依赖
新建一个 Spring Boot 项目,引入以下核心依赖:
<!-- 网关核心依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 服务发现依赖 (以 Nacos 为例) -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 负载均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
启动类保持标准结构即可:
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
配置路由
在 application.yml 中配置路由规则。这里假设服务已注册到 Nacos。
server:
port: 10030
spring:
application:
name: gateway
cloud:
nacos:
discovery:
server-addr: 110.41.51.65:10020
gateway:
routes:
- id: product-service
uri: lb://product-service
predicates:
- Path=/product/**
- id: order-service
uri: lb://order-service
predicates:
- Path=/order/**
配置说明:
id:路由唯一标识。uri:目标服务地址,lb://表示从注册中心获取服务列表并负载均衡。predicates:断言条件,只有匹配该条件的请求才会被路由转发。
访问 http://127.0.0.1:10030/order/1 时,请求会被转发到 order-service。
路由断言工厂 (Route Predicate Factories)
Predicate 是 Java 8 的函数式接口,用于条件过滤。在 Gateway 中,它决定了请求是否匹配某个路由。
默认提供了丰富的断言工厂,支持组合使用。例如,除了路径匹配,还可以限制时间范围:
spring:
cloud:
gateway:
routes:
- id: product-service
uri: lb://product-service
predicates:
- Path=/product/**
- After=2026-01-01T00:00:00.000+08:00[Asia/Shanghai]
这意味着只有在指定时间之后的请求才能通过。更多内置断言可参考官方文档。
过滤器工厂 (Gateway Filter Factories)
Predicate 决定'去哪里',Filter 决定'怎么处理'。过滤器分为 Pre(前置)和 Post(后置)类型,作用范围分为全局(Global)和局部(GatewayFilter)。
局部过滤器
局部过滤器仅对特定路由生效。比如在 product-service 路由下添加参数:
filters:
- AddRequestParameter=userName,bite
这样所有进入 /product/** 的请求都会带上 userName=bite 参数。后端控制器接收时就能拿到这个值。
若希望对所有路由生效,可使用 default-filters 配置:
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Red,Default-Blue
全局过滤器
全局过滤器作用于所有请求,常用于日志、监控或安全校验。Spring Cloud Gateway 内置了一些全局过滤器,如指标监控、负载均衡客户端等。
开启 Actuator 监控端点后,可以查看网关运行时的指标信息:
management:
endpoints:
web:
exposure:
include: "*"
访问 http://127.0.0.1:10030/actuator 即可查看。
过滤器执行顺序
当项目中同时存在多种过滤器时,它们会被合并成一个过滤器链并按优先级排序。每个过滤器都有 order 值,数值越小优先级越高。
执行顺序大致遵循:defaultFilter > GatewayFilter > GlobalFilter。自定义过滤器时,建议通过 @Order 注解或实现 Ordered 接口明确指定优先级,避免逻辑冲突。
自定义过滤器
实际业务中,内置过滤器往往不够用,我们需要自定义逻辑。同样支持 GatewayFilterFactory 和 GlobalFilter 两种扩展方式。
自定义 GatewayFilter
继承 AbstractGatewayFilterFactory 即可。下面是一个示例,记录请求前后的日志:
@Slf4j
@Service
public class CustomGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomConfig> implements Ordered {
public CustomGatewayFilterFactory() {
super(CustomConfig.class);
}
@Override
public GatewayFilter apply(CustomConfig config) {
return ((exchange, chain) -> {
log.info("[Pre] Filter Request, name: {}", config.getName());
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("[Post] Response Filter");
}));
});
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
配合配置类 CustomConfig 和 YAML 配置使用:
filters:
- name: Custom
args:
name: custom filter
自定义 GlobalFilter
实现 GlobalFilter 接口即可,无需额外配置,会自动应用到所有路由:
@Slf4j
@Service
public class CustomGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("[Pre] CustomGlobalFilter enter...");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("[Post] CustomGlobalFilter return...");
}));
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
总结
Spring Cloud Gateway 为微服务架构提供了高性能的统一入口。通过合理配置路由断言和过滤器,我们可以灵活地实现鉴权、限流、日志追踪等横切关注点。在实际开发中,理解过滤器的执行顺序和自定义扩展机制,能帮助我们构建更健壮的系统。

