Spring Cloud Gateway 微服务网关:路由、断言、过滤器

一、网关核心定位:微服务统一流量入口

在微服务架构中,后端会拆分出订单、支付、用户等多个独立服务,前端无法维护海量服务 IP 与端口,Spring Cloud Gateway 应运而生,作为整个业务集群的唯一访问入口。

官方推荐基于 WebFlux 响应式 Server,而非传统 SpringMVC,依托非阻塞异步模型,网关拥有更高并发承载能力,核心职责如下:

  1. 统一入口:前端仅对接网关地址,屏蔽后端集群部署细节;
  2. 路由转发:根据匹配规则将请求分发至对应微服务;
  3. 负载均衡:搭配 Spring Cloud LoadBalancer 实现服务集群负载;
  4. 通用能力收敛:统一处理跨域、请求校验、响应封装、身份令牌等通用逻辑;
  5. 流量管控:可扩展实现限流、鉴权、黑白名单、监控告警。

负载均衡依赖说明

新版 Spring Cloud 已移除内置 Ribbon,负载均衡能力独立为spring-cloud-loadbalancer,必须手动引入 Maven 依赖才能使用lb://负载均衡协议:

xml 复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

重要开发规范

使用 OpenFeign 远程调用时, @FeignClient修饰的接口不能添加类级别@RequestMapping,路径注解仅允许写在接口方法上,否则会出现路径拼接错乱、404 等异常。

微服务调用链路区分

  1. 默认场景:服务之间通过注册中心直连调用,不经过网关,性能更高;
  2. 强制走网关 :修改@FeignClient的 value 为网关服务名,同步调整接口请求路径,适用于需要网关统一鉴权的场景。

二、路由:网关转发的基础规则

路由是网关最基础的组件,由唯一 ID、目标服务地址、匹配断言、过滤器四部分组成,配置存放于application-route.yml

yml 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: order-route # 路由唯一标识,不可重复
          uri: lb://service-order # lb代表负载均衡,指向注册中心订单服务
          predicates: # 路由匹配断言
            - Path=/order/**
          order: 0

路由匹配优先级规则:配置未手动指定order数值时,自上而下依次匹配,请求命中第一条符合断言的路由即转发。 配置order字段优先级按照从小到大以此降低,0优先级最高。

三、路由断言:精准匹配请求的判断器

断言(Predicate)本质是一套请求匹配规则,只有请求满足当前路由全部断言条件,才会转发至对应服务,底层统一由RoutePredicateFactory工厂生成。

1. 官方内置常用断言

表格

断言类型 匹配逻辑
After / Before / Between 根据请求时间匹配,限定访问时段
Cookie 校验请求携带 Cookie,支持正则匹配值
Header 校验指定请求头,支持正则
Host 匹配访问域名
Method 限定 HTTP 请求方式(GET/POST 等)
Path 匹配请求路径,最常用断言
Query 校验 URL 携带的查询参数
RemoteAddr 限制客户端访问 IP 段
Weight 基于权重实现灰度负载均衡

2. 自定义断言工厂实战

内置断言无法满足业务时,可自定义断言工厂,命名规范为XXXRoutePredicateFactory,继承AbstractRoutePredicateFactory。文中VipRoutePredicateFactory实现自定义参数匹配断言:校验请求携带指定参数且值完全匹配,仅 VIP 用户可访问对应路由。核心实现要点:

  1. 内部静态 Config 类承载配置参数,配合@NotEmpty做参数校验;
  2. shortcutFieldOrder定义 yml 短配置参数顺序;
  3. apply方法编写匹配逻辑,从请求中读取参数完成比对。
java 复制代码
package cn.ecut.gateway.predicate;

import jakarta.validation.constraints.NotEmpty;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

@Component
public class VipRoutePredicateFactory extends AbstractRoutePredicateFactory<VipRoutePredicateFactory.Config> {

    public VipRoutePredicateFactory() {
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("param","value");
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {

            @Override
            public boolean test(ServerWebExchange exchange) {
                //localhost/search?q=haha&user=liu
                ServerHttpRequest request = exchange.getRequest();
                String first= request.getQueryParams().getFirst(config.param);
                return StringUtils.hasText(first)&& first.equals(config.value);
            }
         };
    }
    /**
     * 可以配置的参数
     */
    @Validated
    public static class Config {
        @NotEmpty
        private  String param;
        @NotEmpty
        private String value;

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }

        public String getParam() {
            return param;
        }

        public void setParam(String param) {
            this.param = param;
        }

    }
}

四、过滤器:请求与响应的统一处理器

过滤器负责对转发前后的请求、响应做加工处理,分为全局默认过滤器 (所有请求执行)和路由自定义过滤器(仅当前路由生效)。自定义过滤器需继承对应过滤器工厂父类,类名与 yml 配置名称保持一致。

1. 父类区分

  • AbstractGatewayFilterFactory:通用自定义过滤器,支持多参数自定义配置;
  • AbstractNameValueGatewayFilterFactory:键值对专用过滤器,简化name=value格式配置。

2. 实战:一次性令牌过滤器 OnceTokenGatewayFilterFactory

基于AbstractNameValueGatewayFilterFactory开发,依托 WebFlux 响应式异步 API,在请求处理完成后,给响应头自动注入一次性令牌:

  1. 后置逻辑放在chain.filter(exchange).then()中,保证响应生成后修改 Header;
  2. 支持两种令牌模式:uuid 随机串、固定 jwt 标识;
  3. yml 配置格式:OnceToken=自定义头名称,令牌类型

完整核心代码:

java 复制代码
package cn.ecut.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.UUID;
/**
 * 响应式api都是异步的
 */
@Component
public class OnceTokenGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                //每次打开,添加一个一次性令牌,支持uuid,jwt等各种格式
                return chain.filter(exchange).then(
                        Mono.fromRunnable(() -> {
                            ServerHttpResponse response = exchange.getResponse();
                            HttpHeaders headers = response.getHeaders();
                            String value = config.getValue();
                            if("uuid".equalsIgnoreCase(config.getValue())){ //不分大小写
                                value= UUID.randomUUID().toString();
                            }
                            if("jwt".equalsIgnoreCase(config.getValue())){
                                value="jwt";
                            }
                            headers.add(config.getName(), value);
                        })
                );
            }
        };
    }
}

五、网关全局跨域 CORS 配置

单体项目可在 Controller 添加@CrossOrigin解决跨域,微服务架构推荐统一在网关配置全局跨域,避免每个服务重复开发。基础配置示例:

yml 复制代码
spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]': # 全局所有路径生效
            allowedOrigins: "*" # 允许所有前端域名(生产环境建议指定域名)
            allowedMethods: "*" # 放行全部请求方式

生产优化提示:allowedOrigins: *存在安全风险,应填写前端固定域名;开启allowCredentials携带 Cookie 时,禁止使用通配符域名。

六、整体总结与落地思路

Spring Cloud Gateway 是微服务架构的流量枢纽,整套体系由路由、断言、过滤器三大核心组件构成:

  1. 路由:定义转发目标,实现流量分发;
  2. 断言:精细化控制哪些请求可以走当前路由;
  3. 过滤器:统一拦截改造请求、响应,实现跨域、令牌下发、日志、鉴权等通用逻辑。

依托响应式非阻塞架构,网关具备高性能优势,同时提供标准化扩展接口,支持自定义断言、过滤器灵活拓展业务能力。开发过程中需要遵循负载均衡依赖、Feign 注解、响应式后置处理等规范,规避常见 404、响应头失效、参数匹配异常等问题。

在实际项目中,可基于本文自定义组件拓展能力:结合令牌过滤器实现网关统一鉴权、自定义 IP 断言实现访问黑白名单、全局过滤器统一打印请求日志,将所有与业务无关的流量处理逻辑收敛至网关,大幅简化后端微服务开发成本。

相关推荐
lwx572803 小时前
探秘InnoDB:搞懂它的内存、线程、磁盘与日志刷盘策略
java·后端
Flynt4 小时前
从Spring Boot 4.0升到4.1,我在Maven和gRPC上栽了跟头
java·spring boot·后端
plainGeekDev5 小时前
Activity 间传值 → Navigation 参数
android·java·kotlin
plainGeekDev5 小时前
onActivityResult → ActivityResult API
android·java·kotlin
Sunia5 小时前
《AgentX 专栏》10-生产部署:3台2C4G云服务器把企业级Agent真正跑起来的完整方案
java·架构
ZhengEnCi6 小时前
J7A-高级Java工程师面试三道灵魂拷问-深度广度与工程素养的终极检验
java·后端
狼爷1 天前
吃透 Java Function 接口,搞定 99% 的 Stream 场景
java·函数式编程
祎雪双十Gy1 天前
从 DataX 的配置加载说起:我用 FastJson2 做了一个轻量级动态配置管理库
java·后端
小锋java12341 天前
分享一套锋哥原创的SpringBoot4+Vue3宠物领养网站系统
java