1. 引言
在微服务架构中,一个系统往往被拆分成多个独立的服务,每个服务负责各自的业务领域。随着服务数量的增长,客户端直接调用各个服务会面临诸多问题:服务地址分散难以管理、认证鉴权逻辑重复、跨域处理繁琐、流量控制困难等。API 网关作为系统的统一入口,正是为了解决这些问题而诞生的。
Spring Cloud Gateway 是 Spring 官方基于 Spring WebFlux 和 Project Reactor 构建的响应式 API 网关,它提供了路由转发、断言(Predicate)匹配、过滤器(Filter)链等核心能力,是目前 Spring Cloud 微服务体系中主流的网关解决方案。
本文将从零开始,带你一步步掌握 Spring Cloud Gateway 的入门使用,并深入剖析其核心功能的实现原理。
2. 为什么需要 API 网关
在引入 Spring Cloud Gateway 之前,我们先理解网关在微服务架构中的定位。
2.1 没有网关的痛点
假设系统拆分为用户服务、订单服务、商品服务三个微服务,客户端需要分别维护三个服务的地址:
http://user-service:8081 http://order-service:8082 http://product-service:8083这会带来以下问题:
- 地址分散:客户端需要感知每个服务的具体地址,服务地址变更时客户端也要跟着改。
- 重复逻辑:认证、鉴权、日志、限流等横切逻辑在每个服务中都要实现一遍。
- 安全暴露:所有服务端口直接暴露给外部,攻击面增大。
- 无法统一管控:流量控制、灰度发布、熔断降级等能力难以在全局层面统一实施。
2.2 网关的职责
引入网关后,客户端只与网关通信,由网关负责请求的路由与转发:
客户端 --> 网关 --> 用户服务 --> 订单服务 --> 商品服务网关承担的核心职责包括:
- 统一入口:所有外部请求先经过网关,再分发到下游服务。
- 路由转发:根据请求路径、参数等条件,将请求转发到对应的服务。
- 横切能力:在转发前后执行统一的认证、鉴权、日志、限流等逻辑。
- 协议转换:支持 HTTP、WebSocket 等多种协议的统一接入。
3. Spring Cloud Gateway 核心概念
在动手写代码之前,先了解 Gateway 的三个核心概念:路由(Route)、断言(Predicate)和过滤器(Filter)。
3.1 路由(Route)
路由是网关的基本组成单元,由以下部分组成:
- ID:路由的唯一标识。
- URI:目标服务的地址,即请求最终转发到哪里。
- 断言(Predicate):匹配条件,决定哪些请求走这条路由。
- 过滤器(Filter):在请求转发前后执行的逻辑。
一条路由可以理解为:当请求满足某个条件时,将其转发到某个目标地址,并在过程中执行一系列过滤器。
3.2 断言(Predicate)
断言用于匹配 HTTP 请求的各种属性,例如路径、请求头、查询参数、请求方法等。当断言条件满足时,请求才会被该路由处理。
Spring Cloud Gateway 内置了多种断言工厂,常用的包括:
- Path 断言:按请求路径匹配,如
/user/**。 - Method 断言:按请求方法匹配,如 GET、POST。
- Header 断言:按请求头匹配。
- Query 断言:按查询参数匹配。
- Cookie 断言:按 Cookie 匹配。
- Host 断言:按域名匹配。
3.3 过滤器(Filter)
过滤器在请求被路由转发的前后执行,用于实现横切逻辑。Gateway 的过滤器分为两类:
- GatewayFilter:作用于单个路由,通过配置绑定到具体路由上。
- GlobalFilter:作用于所有路由,全局生效。
常见的过滤器能力包括:添加请求头、添加响应头、请求重试、熔断降级、限流、鉴权等。
4. 环境准备
在开始编码之前,先准备好开发环境。
4.1 环境要求
- JDK:8 及以上版本。
- Maven:3.6 及以上版本。
- IDE:IntelliJ IDEA 或 Eclipse。
- Spring Boot:2.4 及以上版本(本文以 2.7.x 为例)。
- Spring Cloud:2021.0.x 及以上版本(本文以 2021.0.8 为例)。
4.2 创建项目
通过 Spring Initializr 创建一个新的 Spring Boot 项目,并添加以下依赖:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>注意:Spring Cloud Gateway 基于 WebFlux,不要同时引入spring-boot-starter-web,否则会冲突导致启动失败。
5. 快速入门:第一个路由
下面通过一个最简单的例子,让 Gateway 跑起来。
5.1 编写配置文件
在application.yml中配置一个简单的路由,将/user/**的请求转发到本地的用户服务:
server:port:8080spring:application:name:gateway-servercloud:gateway:routes:-id:user-service-routeuri:http://localhost:8081predicates:-Path=/user/**配置说明:
id:路由 ID,唯一标识。uri:目标服务地址。predicates:断言列表,这里使用Path断言匹配/user/**路径。
5.2 启动验证
启动网关服务后,访问http://localhost:8080/user/info,网关会将请求转发到http://localhost:8081/user/info。
如果本地没有用户服务,可以先启动一个简单的 Spring Boot 服务作为测试目标,或者使用httpbin这类在线测试服务:
spring:cloud:gateway:routes:-id:httpbin-routeuri:http://httpbin.orgpredicates:-Path=/get访问http://localhost:8080/get,网关会转发到http://httpbin.org/get并返回结果。
6. 常用断言工厂详解
断言是路由匹配的核心,下面介绍几种最常用的断言工厂及其配置方式。
6.1 Path 断言
按请求路径匹配,支持 Ant 风格的通配符:
predicates:-Path=/user/**,/order/**6.2 Method 断言
按请求方法匹配:
predicates:-Method=GET,POST6.3 Header 断言
按请求头匹配,第二个参数支持正则表达式:
predicates:-Header=X-Request-Id,\d+6.4 Query 断言
按查询参数匹配,可以只指定参数名,也可以同时校验参数值:
predicates:-Query=page-Query=size,\d+6.5 组合使用
多个断言可以组合使用,请求必须满足所有条件才会被路由匹配:
predicates:-Path=/user/**-Method=GET-Header=X-Request-Id,\d+7. 过滤器(Filter)实战
过滤器是网关实现横切能力的关键。下面介绍几种常用过滤器及自定义过滤器。
7.1 内置过滤器示例
添加请求头:
spring:cloud:gateway:routes:-id:user-service-routeuri:http://localhost:8081predicates:-Path=/user/**filters:-AddRequestHeader=X-Request-From,gateway添加响应头:
filters:-AddResponseHeader=X-Response-From,gateway请求重试:
filters:-name:Retryargs:retries:3statuses:BAD_GATEWAY7.2 自定义全局过滤器
通过实现GlobalFilter和Ordered接口,可以编写全局过滤器。下面实现一个简单的鉴权过滤器:
@ComponentpublicclassAuthGlobalFilterimplementsGlobalFilter,Ordered{@OverridepublicMono<Void>filter(ServerWebExchangeexchange,GatewayFilterChainchain){Stringtoken=exchange.getRequest().getHeaders().getFirst("Authorization");if(token==null||token.isEmpty()){exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);returnexchange.getResponse().setComplete();}returnchain.filter(exchange);}@OverridepublicintgetOrder(){return-100;}}代码说明:
filter方法中编写过滤逻辑,返回Mono<Void>。- 通过
chain.filter(exchange)将请求传递给过滤器链中的下一个过滤器。 getOrder()返回值越小,优先级越高,越先执行。
7.3 自定义局部过滤器
实现GatewayFilterFactory接口可以编写作用于单个路由的过滤器:
@ComponentpublicclassCustomGatewayFilterFactoryextendsAbstractGatewayFilterFactory<CustomGatewayFilterFactory.Config>{publicCustomGatewayFilterFactory(){super(Config.class);}@OverridepublicGatewayFilterapply(Configconfig){return(exchange,chain)->{System.out.println("自定义过滤器,参数:"+config.getName());returnchain.filter(exchange);};}publicstaticclassConfig{privateStringname;// getter / setter}}在配置中使用:
filters:-name:Customargs:name:test8. 核心功能原理解析
掌握了基本使用后,我们来深入剖析 Spring Cloud Gateway 的核心实现原理。
8.1 整体架构
Spring Cloud Gateway 的核心处理流程如下:
整个处理过程基于 Spring WebFlux 的响应式编程模型,全程非阻塞。
8.2 路由匹配原理
路由匹配的核心类是RoutePredicateHandlerMapping。当请求到达时,它遍历所有已注册的路由,逐个执行路由的断言(Predicate)进行匹配:
// RoutePredicateHandlerMapping 核心逻辑(简化)protectedMono<Route>lookupRoute(ServerWebExchangeexchange){returnthis.routeLocator.getRoutes().filter(route->route.getPredicate().test(exchange)).next();}匹配过程说明:
routeLocator.getRoutes()获取所有路由。- 通过
filter逐个执行断言,找到第一个匹配成功的路由。 - 如果没有任何路由匹配,则返回 404。
8.3 过滤器链执行原理
Gateway 的过滤器链基于责任链模式。FilteringWebHandler负责将全局过滤器和路由级过滤器合并,并按照Ordered排序后依次执行:
// FilteringWebHandler 核心逻辑(简化)publicMono<Void>handle(ServerWebExchangeexchange){Routeroute=exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);List<GatewayFilter>gatewayFilters=route.getFilters();List<GatewayFilter>combined=combineGlobalFilters(gatewayFilters);returnnewDefaultGatewayFilterChain(combined).filter(exchange);}过滤器链的执行过程:
每个过滤器在调用chain.filter(exchange)之前是前置逻辑,之后是后置逻辑,从而实现对请求和响应的双向处理。
8.4 请求转发原理
当过滤器链执行完毕后,请求由NettyRoutingFilter转发到下游服务。它基于 Netty 的 HttpClient 发起异步请求,全程非阻塞:
// NettyRoutingFilter 核心逻辑(简化)publicMono<Void>filter(ServerWebExchangeexchange,GatewayFilterChainchain){HttpMethodmethod=request.getMethod();URIurl=exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);// 使用 WebClient 发起异步请求returnthis.webClient.method(method).uri(url).exchange().flatMap(response->writeResponse(exchange,response));}转发过程说明:
- 从 exchange 中取出目标 URL。
- 使用 WebClient 发起异步请求。
- 将下游服务的响应写回客户端。
8.5 响应式编程基础
Spring Cloud Gateway 基于 Project Reactor,核心是Mono和Flux两个响应式类型:
- Mono:表示 0 或 1 个元素的异步序列。
- Flux:表示 0 到 N 个元素的异步序列。
整个网关的处理链路都是异步非阻塞的,因此相比传统的 Servlet 同步模型,Gateway 在并发场景下具有更高的吞吐量和更低的资源占用。
9. 常见问题与注意事项
9.1 不要引入 spring-boot-starter-web
Spring Cloud Gateway 基于 WebFlux,如果同时引入spring-boot-starter-web,会导致项目启动失败或路由不生效。确保只引入spring-cloud-starter-gateway。
9.2 跨域配置
如果前端页面与网关不在同一域名下,需要配置跨域:
spring:cloud:gateway:globalcors:cors-configurations:'[/**]':allowedOrigins:"*"allowedMethods:-GET-POST-PUT-DELETE9.3 与 Nacos 服务发现集成
在实际项目中,网关通常配合注册中心使用,通过服务名进行路由,而不是写死地址:
spring:cloud:gateway:discovery:locator:enabled:trueroutes:-id:user-service-routeuri:lb://user-servicepredicates:-Path=/user/**lb://前缀表示通过负载均衡从注册中心获取服务实例。
10. 总结
本文从微服务架构中网关的定位出发,介绍了 Spring Cloud Gateway 的核心概念、快速入门、常用断言与过滤器,并深入剖析了路由匹配、过滤器链、请求转发等核心原理。
回顾关键要点:
- 路由由 ID、URI、断言和过滤器组成,是网关的基本单元。
- 断言决定请求是否匹配某条路由,支持路径、方法、请求头等多种条件。
- 过滤器实现横切逻辑,分为全局过滤器和路由级过滤器。
- 原理层面,Gateway 基于 WebFlux 响应式模型,通过
RoutePredicateHandlerMapping匹配路由,通过责任链模式执行过滤器,最终由 Netty 异步转发请求。
掌握了这些内容,你就具备了在实际项目中落地 Spring Cloud Gateway 的能力。后续可以进一步探索限流、熔断、灰度发布等高级特性,让网关真正成为微服务架构的坚实入口。