Gateway 过滤器:Global/局部过滤器与跨域
路由解决"去哪",过滤器解决"怎么加工"。网关里的过滤器分为两类:GlobalFilter 对所有路由生效,GatewayFilter 只对挂载它的那条路由生效。横切逻辑(加统一头、统计耗时、鉴权)放全局,局部差异(某个服务要特殊改写)放局部,是常用的划分原则。
过滤器链的执行模型
请求进入网关后依次经过匹配到的路由的过滤器链。执行顺序由 order 值决定,值越小越先执行;过滤器在转发前执行的部分叫 pre,在响应返回后执行的部分叫 post,一个过滤器可以同时包含两段逻辑(转发前做事、拿到响应后再做事)。理解顺序很重要:鉴权必须最先执行,限流应在鉴权之后、转发之前。
内置局部过滤器示例
局部过滤器在路由配置里用 "- 名称=参数" 或 "- name + args" 两种写法声明,常用内置过滤器包括:StripPrefix(去前缀)、AddRequestHeader/AddResponseHeader(加请求/响应头)、PrefixPath(加前缀)、RewritePath(正则改写路径)、SetStatus(改状态码)。例如给 user 路由加自定义头:
filters:
- StripPrefix=1
- AddRequestHeader=X-Source, gateway
- AddResponseHeader=X-Resp-Time, ${responseTime}
内置过滤器清单与参数含义以官方文档为准,它们大多短小且可组合,先查清单再考虑自己造轮子。
自定义全局过滤器:统计耗时
自定义过滤器只需实现 GlobalFilter 与 Ordered 两个接口,chain.filter 之前是 pre、之后通过 then 追加 post 逻辑:
@Component
public class TimingGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
long start = System.currentTimeMillis();
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
long cost = System.currentTimeMillis() - start;
exchange.getResponse().getHeaders().add("X-Cost", String.valueOf(cost));
}));
}
@Override
public int getOrder() {
return -100; // 负数让它在多数过滤器之前执行
}
}
局部自定义过滤器的思路
要让过滤器只作用于某条路由、并支持在 yaml 里像内置过滤器一样声明,需要实现 GatewayFilterFactory 抽象类,按"前缀 + GatewayFilterFactory"命名(如 TimeLimitGatewayFilterFactory 对应配置名 TimeLimit)。相比全局过滤器它多一步工厂注册,但可配置性更好。具体编写范式以官方文档为准。
跨域(CORS)配置
前端页面跨域调用网关是最常见的诉求。网关层统一配置即可,无需在每个服务上重复处理:
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowed-origins:
- "https://example.com"
allowed-methods: "*"
allowed-headers: "*"
allow-credentials: true
max-age: 3600
要点:allowed-origins 不要写成 "*" 的同时 allow-credentials 为 true(浏览器规范不允许);带 Cookie 的跨域请求必须 allow-credentials=true 并明确列出可信来源;预检请求(OPTIONS)由网关自动应答,不需要业务服务处理。生产环境建议把可跨域来源收敛为白名单,来源变更通过配置中心下发(第 11 章)。
小结
过滤器体系让网关成为"可编程的入口":全局过滤器承接横切逻辑,局部过滤器承接路由差异,order 控制顺序,globalcors 一处解决跨域。下一章在过滤器链上实现最典型的能力之一——限流。