文章目录
需求引出
网络拓扑图
Gateway是什么
技术基础: 基于Spring生态系统构建的API网关服务,核心技术包括Spring 5、Spring Boot 2和Project Reactor
设计目标: 提供简单有效的API路由方式,并内置强大的过滤器功能
核心特性:
路由功能: 支持灵活的API请求路由配置
过滤器链: 提供熔断、限流、重试等分布式系统关键功能
生态兼容: 天然支持Spring/Spring Boot技术栈,与Spring Cloud生态无缝集成
官网
官网:https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway-server-webflux/how-it-works.html
快速集成:
依赖配置: 使用org.springframework.cloud:spring-cloud-starter-gateway作为starter
禁用方式: 通过spring.cloud.gateway.enabled=false可禁用网关功能
技术前提: 需要熟悉Spring Boot 2.x、Spring WebFlux和Project Reactor等响应式编程技术
3.Gateway核心功能
流量控制: 支持精细化的请求流量管理和限制
熔断机制: 提供系统级故障隔离和恢复能力
日志系统: 完整的请求日志记录和监控能力
反向代理: 作为系统入口统一处理请求转发
实践建议: 根据实际项目需求选择性地集成特定功能模块
Gateway VS Zuul
定位差异:SpringCloud Gateway是Spring Cloud生态系统中的网关组件,设计目标就是替代Zuul
技术架构:
基于Spring WebFlux框架实现
底层采用Reactor模式通信框架Netty
性能优势:相比Zuul具有更强大的性能表现
1Gateway的特性
框架基础:
基于Spring Framework构建
支持Spring WebFlux
整合Project Reactor和Spring Boot
核心功能:
动态路由:根据请求URL动态决定转发目标
断言机制:通过Predicate判断请求是否可处理
过滤器链:支持请求前/后的处理逻辑
服务发现:集成Spring Cloud服务注册发现
熔断保护:内置Hystrix断路器功能
流量控制:支持请求限流功能
路径重写:可按规则修改请求路径
二、使用网关服务架构重构
核心价值:
提供统一API入口,通过URL路由转发请求
集成负载均衡、限流、熔断、鉴权等能力
实现原理:
动态路由配置:通过断言+过滤器实现请求分发
服务发现集成:自动识别可调用的后端服务
路径重写机制:按业务需求修改请求路径
Gateway基本原理
Route路由
组成要素:由ID、目标URI、断言集合和过滤器集合构成
匹配条件:当所有断言结果为true时,该路由才会被匹配
本质特征:代表一个完整的请求路径或接口配置
Predicate断言
匹配对象:对HTTP请求头、请求参数等所有内容进行匹配
路径示例:配置$-Path=/member/get/^{**}$表示匹配所有以/member/get/开头的请求
匹配流程:请求路径必须完全符合配置模式才会进行路由转发
典型场景:如请求http://localhost/member/get/1能匹配,而http://localhost/member/xxx/1则不能匹配
Filter过滤
处理时机:可在请求被路由前或路由后进行额外处理
工作流程:在断言匹配成功后触发过滤机制
参数添加示例:配置filters:-AddRequestParameter=color,blue会在匹配请求中添加color=blue参数
处理效果:如原始请求http://localhost:10000/member/get/1会被处理为http://localhost:10000/member/get/1?color=blue
类比说明:类似Java Web中的过滤器机制,包含预处理和后处理阶段
Gateway工作机制
客户端为啥不能直接用 IP + 端口?
直接暴露微服务 IP + 端口,相当于 “把家门钥匙给陌生人”,容易被攻击。
网关作为中间层,隐藏了内部服务的真实地址,相当于 “家门有保安,陌生人进不来”。
核心工作流程:快递包裹的 “分拣 - 运输 - 签收” 三步曲
快递到达分拣中心(用户点击网页按钮, 根据域名[通过查找DNS服务器]找到网关所在的IP地址, 请求达到网关)
->根据快递单地址确定要送到哪个小区(根据快递单URL找到匹配的断言规则,确定目标服务名
->分拣中心给包裹贴标签, 检查包装是否完好, 确认你有没有寄件资格(Pre过滤器添加请求参数, 参数检验, 权限校验)
->分拣中心安排快递员把包裹送到小区(Gateway 通过 Ribbon 从 Eureka 找服务地址,负载均衡选一个实例转发请求。)
->包裹送到后,分拣中心记录签收时间(日志)、更新物流状态(修改响应头)。
二、过滤器链:快递处理的 “流水线工人
Pre 过滤器:发货前的 “质检团队”
做这些事:
检查地址是否正确(参数校验):比如你写的 “北京市朝阳区” 是否真实存在。
查你有没有寄件权限(JWT 令牌验证):像寄国际快递需要护照,没护照不让寄。
统计今天寄了多少包裹(流量监控):防止一天寄太多包裹,分拣中心忙不过来(限流)。
贴统一标签(AddRequestParameter):比如所有包裹都贴 “易碎品” 标签。
Post 过滤器:签收后的 “售后团队”
做这些事:
把物流信息统一写成 “已签收” 格式(修改响应内容):不管哪个快递员送的,格式都一样。
给包裹加 “好评” 标签(添加响应头):比如跨域请求时加Access-Control-Allow-Origin头。
记录包裹送了多久(响应耗时统计):比如从分拣中心到你家花了 30 分钟。
客户端向SpringCloud Gateway发出请求,然后在Gateway Handler Mapping 断言 中找到与请求相匹配的路由,将其发送到Gate Web Handler。
Handler通过指定的过滤器链将请求发送到实际的目标服务。
Filter在“pre”类型的过滤器中可以做参数校验,权限校验,流量监控,日志输出,协议转换。
在“post”类型的过滤器中可以做响应内容,响应头修改,日志输出,流量监控。,
搭建Gateway微服务
需求
网关本身也是一个微服务模块,可视为Eureka Client
实现
1.对80服务消费方的一个升级,粘过来。
创建依据:参照member-service-consumer-80创建e-commerce-gateway-20000微服务
原因:网关服务本质上是服务调用方的升级版本,具有更强的功能特性
POM文件修改:从member-service-consumer-80的pom.xml拷贝部分内容
关键依赖:必须引入spring-cloud-starter-gateway场景启动器
模块命名:e-commerce-gateway-20000
目录结构:需与父工程e-commerce保持统一
版本管理:使用父工程声明的版本仲裁机制(Hoxton.SR1)
依赖刷新:创建完成后必须刷新Maven以确保依赖正确加载
版本验证:通过Maven管理器可查看实际加载版本为2.2.1.RELEASE
application.yml配置
版本控制机制:通过spring-cloud-dependencies统一管理网关版本
依赖继承关系:网关属于Spring Cloud原生组件,非Alibaba体系
工程结构验证:创建后需确认模块已被父工程正确聚合管理
配置要点:路由ID需保持唯一,最终访问URL由uri+Path组合而成
关键依赖:必须引入spring-cloud-starter-netflix-eureka-client实现服务发现
版本继承:通过父项目spring-cloud-dependencies-Hoxton.SR1进行版本仲裁
冲突说明:若同时引入web相关依赖会导致启动失败,必须特别注意
Gateway服务不需要Web Starter
禁止引入项:
spring-boot-starter-web
spring-boot-starter-actuator
冲突原因:Gateway作为服务网关,其底层实现与Web容器存在不兼容
典型错误:初学者常误加这些依赖导致启动失败
解决方案:在pom.xml中严格检查并移除相关依赖
Lombok依赖的添加
推荐配置:可添加optional true限定作用域
作用范围:仅限当前项目使用,避免传递依赖
格式化要求:添加后需执行Maven刷新操作
必要依赖:需要保留e_commerce_center-common-api模块
版本管理:使用${project.version}保持版本一致
模块作用:提供跨服务公共接口定义
网关微服务搭建:把 “前台接待” 升级成 “智能导览机器人”
1.新建微服务模块e-commerce-gateway-20000
2.pom依赖
只有 Eureka Server 自己需要eureka-server依赖
,其他微服务只需要eureka-client
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.zzw</groupId>
<artifactId>e-commerce</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>e-commerce-gateway-20000</artifactId>
<!--引入相关的依赖-->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--引入e-ecommerce-center-common-api-->
<dependency>
<groupId>com.zzw</groupId>
<artifactId>e-ecommerce-center-common-api</artifactId>
<version>${project.version}</version>
</dependency>
<!--引入eureka client 场景启动器starter-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--引入gateway场景启动器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
</project>
3.配置文件
server:
port: 20000
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由。List<RouteDefinition> routes 数组
# 最终的路径 uri+Path,这里暂时用不到 eureka server(意思就是 网关直接把请求转发到http://localhost:10000,不通过 Eureka 动态发现服务。)
- id: member-gateway-route-01
uri: http://localhost:10000
predicates:
- Path=/member/provider/**
eureka:
instance:
hostname: e-commerce-service # 服务别名
client:
service-url:
register-with-eureka: true
fetch-registry: true
# Eureka 注册中心是一栋楼
# http://eureka9001.com:9001是注册中心的地址
# /eureka/就是这栋楼里 “通讯录办公室” 的具体房间号。
# 将本服务注册到eureka集群
defaultZone: http://eureka9001.com:9001/eureka/, http://eureka9002.com:9002/eureka/
4.启动类
@EnableEurekaClient
@SpringBootApplication
public class MemberGatewayApplication20000 {
public static void main(String[] args) {
ConfigurableApplicationContext ioc = SpringApplication.run(MemberGatewayApplication20000.class, args);
}
}
5.测试
先用原来的测一下
测试一下服务网关
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由。List<RouteDefinition> routes 数组
- id: member-gateway-route-01
#gateway 最终访问的url是 url=uri+Path
#匹配后提供服务的路由地址: 也可以是外网 http://www.baidu.com
#比如: 如果客户端/浏览器 访问gateway 的 url http://localhost:20000/member/provider/selectById/1
#匹配Path成功, 最终访问的url 就是 http://localhost:10000/member/provider/selectById/1
#如果匹配失败, gateway返回404信息
#(这里配置的uri是固定的, 意思就是 网关直接把请求转发到http://localhost:10000,不通过 Eureka 动态发现服务。)
uri: http://localhost:10000
predicates:
- Path=/member/provider/selectById/**
- id: member-gateway-route-02
uri: http://localhost:10000
predicates:
#这时如果客户端/浏览器 访问gateway 的 url http://localhost:20000/member/provider/insert
#匹配Path成功, 最终访问的url 就是 http://localhost:10000/member/provider/insert
- Path=/member/provider/insert
- id: member-gateway-route-03 #路由id,自己配置,要求唯一
uri: http://www.baidu.com
predicates: # 断言,可以有多种形式
- Path=/
断言类型
- Path=/member/provider/selectById/** 属于yaml语法哪一种类型
Gateway 路由断言:快递分拣中心的「10 种分拣规则」
gateway路由配置
新建src/main/java/com/zzw/springcloud/config/GatewayRoutesConfig.java
@Configuration
public class GatewayRoutesConfig {
/*
用配置类的方式配置路由
- id: member-gateway-route-01
uri: http://localhost:10000
predicates:
- Path=/member/provider/selectById/**
*/
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
RouteLocatorBuilder.Builder routes = builder.routes();
/*
public Builder route(String id, Function<PredicateSpec, Route.AsyncBuilder> fn) {
Route.AsyncBuilder routeBuilder = fn.apply(new RouteSpec(this).id(id));
add(routeBuilder);
return this;
}
1.java中函数式接口的典型用法, 传统的匿名类实现
2.一个函数式接口(Function<PredicateSpec, Route.AsyncBuilder>),用于定义路由规则。
3.接受的是 PredicateSpec,返回的是 Route.AsyncBuilder
4.predicateSpec -> predicateSpec.path("/member/provider/selectById/**").uri("http://localhost:10000"); 就是lambda表达式
(1)PredicateSpec是Gateway提供的路由断言配置接口
(2)Route.AsyncBuilder是Gateway提供的路由构建器, 用于设置路由断言和路由地址
========================================================================================
Function<PredicateSpec, Route.AsyncBuilder> fn = new Function<PredicateSpec, Route.AsyncBuilder>() {
@Override
public Route.AsyncBuilder apply(PredicateSpec predicateSpec) {
return predicateSpec.path("/member/provider/selectById/**").uri("http://localhost:10000");
}
};
========================================================================================
//对上面进行简化,lambda表达式的第一种写法
Function<PredicateSpec, Route.AsyncBuilder> fn2 = (predicateSpec) -> {return predicateSpec.path("/member/provider/selectById/**").uri("http://localhost:10000");};
//对上面进行简化,lambda表达式的第二种写法
Function<PredicateSpec, Route.AsyncBuilder> fn3 = predicateSpec -> predicateSpec.path("/member/provider/selectById/**").uri("http://localhost:10000");
*/
Function<PredicateSpec, Route.AsyncBuilder> fn = (predicateSpec) -> {return predicateSpec.path("/member/provider/selectById/**").uri("http://localhost:10000");};
Function<PredicateSpec, Route.AsyncBuilder> fn2 = (predicateSpec) -> {return predicateSpec.path("/member/provider/insert").uri("http://localhost:10000");};
Function<PredicateSpec, Route.AsyncBuilder> fn3 = (predicateSpec) -> {return predicateSpec.path("/").uri("http://www.baidu.com");};
RouteLocatorBuilder.Builder route = routes
.route("member-gateway-route-01", predicateSpec -> predicateSpec.path("/member/provider/selectById/**").uri("http://localhost:10000"))
.route("member-gateway-route-02", predicateSpec -> predicateSpec.path("/member/provider/insert").uri("http://localhost:10000"))
.route("member-gateway-route-03", predicateSpec -> predicateSpec.path("/").uri("http://localhost:10000"));
return route.build();
}
}
lambda表达式理解,新建src/test/java/com/zzw/springcloud/TestFunction.java
public class TestFunction {
public static void main(String[] args) {
//第一种写法 传统匿名类实现
//Dog dog = hi("小花猫,喵喵喵~", new Function<String, Cat>() {
// @Override
// public Cat apply(String str) {
// Cat cat = new Cat();
// cat.setName(str);
// return cat;
// }
//});
//lambda表达式的第一种写法
//Dog dog = hi("小花猫,喵喵喵~", (str) -> {
// Cat cat = new Cat();
// cat.setName(str);
// return cat;
// }
//);
//对上面的lambda表达式进行简化
//Dog dog = hi("小花猫,喵喵喵~", str -> {
// Cat cat = new Cat();
// cat.setName(str);
// return cat;
// }
//);
//对上面的lambda表达式进行简化
//Dog dog = hi("小花猫,喵喵喵~", str -> {
// return new Cat(str);
// }
//);
//对上面的lambda表达式进行简化
Dog dog = hi("小黄猫,喵喵喵~", r -> new Cat(r));
System.out.println(dog.getName());
}
/*
public Builder route(String id, Function<PredicateSpec, Route.AsyncBuilder> fn) {
Route.AsyncBuilder routeBuilder = fn.apply(new RouteSpec(this).id(id));
add(routeBuilder);
return this;
}
*/
public static Dog hi(String str, Function<String, Cat> fn) {
Cat cat = fn.apply(str);
Dog dog = new Dog();
dog.setName(cat.getName() + " 返回了一只小狗~");
return dog;
}
}
class Dog {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class Cat {
private String name;
public Cat() {
}
public Cat(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
动态路由需求
动态路由 lb://member-service-provider, 通过底层负载均衡调用
需要注意服务名应使用小写字母,大写字母会导致配置失败。lb是协议名,代表负载均衡协议,后面的内容是对应路径的服务名称,也是小写字母。
spring:
application:
name: e-commerce-gateway
cloud:
gateway:
routes: # 配置路由,可以配置多个路由。List<RouteDefinition> routes 数组
- id: member-gateway-route-04
uri: lb://member-service-provider
predicates:
- name: Path
args:
pattern: /member/provider/**
discovery:
locator:
enabled: true
配置负载均衡算法
BestAvailableRule: 选择并发请求最小的server。会逐个考察Server,如果Server被tripped(跳闸)则忽略,最终选择ActiveRequestsCount最小的server。
AvailabilityFilteringRule: 过滤掉因连接失败被标记为circuit tripped的后端server,同时过滤高并发server(active connections超过配置阈值)。
WeightedResponseTimeRule: 根据响应时间分配权重,响应时间越长weight越小,被选中的可能性越低。
RetryRule: 在选定负载均衡策略基础上增加重试机制。配置时间段内若选择server不成功,会持续尝试使用subRule选择可用server。
RoundRobinRule: 轮询index选择对应位置的server(Ribbon默认算法)。
RandomRule: 随机选择server,在index上随机选取对应位置。
ZoneAvoidanceRule: 复合判断server所在区域的性能和可用性来选择server。
@Configuration
public class RibbonRule {
//配置和注⼊⾃定义的负载均衡算法
//可以选择多种负载均衡算法,如RandomRule(随机选择)、RoundRobinRule(轮询)等。
//
@Bean
public IRule getRibbonRule() {
return new RandomRule();
}
}
配置启动类
@RibbonClient(name = "member-service-provider", configuration = RibbonRule.class)
Predicate断言
基本介绍
工厂类型:
After:基于请求时间的"之后"断言
Before:基于请求时间的"之前"断言
Between:时间区间断言
Cookie:检查请求Cookie
Header:检查请求头
Host:检查请求主机
Method:检查请求方法(GET/POST等)
Path:检查请求路径
Query:检查查询参数
RemoteAddr:检查远程地址
Weight:权重路由
核心特性:
内置多种工厂类型:共11种标准断言工厂
多属性匹配:每种工厂匹配HTTP请求的不同属性
组合使用:支持通过逻辑与(and)组合多个断言条件
实现原理:
Spring Cloud Gateway创建Route对象时
使用RoutePredicateFactory创建Predicate对象
Predicate对象赋值给Route进行路由匹配
创建过程:
使用RoutePredicateFactory创建Predicate对象
将Predicate对象赋值给Route对象
After Route Predicate
时间断言:After Route Predicate根据时间进行断言,只有指定时间之后的请求才会被处理
典型需求:要求只有2022-11-18 12:35:50之后的请求才进行匹配转发,不满足时间条件的请求不予处理
时间格式:必须使用特定格式,包含年月日时分秒毫秒和时区,如:
- After=2022-11-18T12:35:50.000+08:00[Asia/Shanghai]
- id: member-gateway-route-03
uri: lb://member-service-provider
predicates:
- name: After
args:
date-time: 2025-06-29T16:59:00.493+08:00[Asia/Shanghai]
Before Route Predicate
核心功能:只处理指定时间点之前的请求,不满足时间条件的请求将被拒绝
时间格式:采用标准ISO时间格式,如
- Before=2022-11-18T12:35:50.000+08:00[Asia/Shanghai]
应用场景:适用于需要限制特定时间后停止服务的业务场景
- id: member-gateway-route-03
uri: lb://member-service-provider
predicates:
- name: Before
args:
date-time: 2025-06-29T16:59:00.493+08:00[Asia/Shanghai]
Between Route Predicate
- id: member-gateway-route-04
uri: lb://member-service-provider
predicates:
- name: Between
args:
datetime1: 2025-06-29T17:02:00.493+08:00[Asia/Shanghai]
datetime2: 2025-06-29T17:15:00.493+08:00[Asia/Shanghai]
Cookie Route Predicate
- id: member-gateway-route-04
uri: lb://member-service-provider
predicates:
- name: Cookie
args:
name: auth
regexp: token=.*
Host Route Predicate
Host Route Predicate 网关的「域名安检员」指南
- id: member-gateway-route-04
uri: lb://member-service-provider
predicates:
- name: Host
args:
patterns: [localhost, 127.0.0.1, www.zzw.com]
Method Route Predicate
Method Route Predicate:网关的「请求方式守门人」
- id: member-gateway-route-04
uri: lb://member-service-provider
predicates:
- name: Method
args:
methods: [GET, POST]
Path Route Predicate
Path Route Predicate:网关的「路径导航员」
- id: member-gateway-route-04
uri: http://localhost:10000
predicates:
- name: Path
args:
pattern: /member/provider/**
Query Route Predicate
Query Route Predicate:网关的「参数安检仪」指南
- id: member-gateway-route-04
uri: http://localhost:10000
predicates:
- name: Query
args:
param: name
regexp: zzw
RemoteAddr Route Predicate
- id: member-gateway-route-04
uri: http://localhost:10000
predicates:
- name: RemoteAddr
args:
sources: [127.0.0.1, 192.168.1.100]
Weight
不测试, 太麻烦
Filter过滤器链
Spring Cloud Gateway 过滤器:请求处理的 “全能管家”
基本介绍
实例
GatewayFilter 类型详解:请求与响应的定制化处理工具
一、AddRequestParameter GatewayFilter Factory:给请求加 “小纸条”
功能作用:在匹配请求的查询字符串中添加指定参数
参数格式:采用name-value对形式,如AddRequestParameter=red, blue
URI变量支持:支持使用路径匹配中的URI变量,运行时自动展开
层级关系:与routes下的id、uri、predicates同级
多参数配置:可通过多个AddRequestParameter配置多个参数,如同时添加color和address参数
二、AddRequestHeader GatewayFilter Factory:给请求 “戴帽子”
功能区别:与AddRequestParameter类似,但操作的是请求头而非查询参数
配置格式:AddRequestHeader=X-Request-Red, Blue
典型应用:用于添加认证头、追踪ID等HTTP头信息
三、AddResponseHeader GatewayFilter Factory:给响应 “贴封印”
响应处理:在返回给客户端的响应中添加指定头信息
使用场景:常用于添加缓存控制、安全策略等响应头
- id: member-gateway-route-04
uri: lb://member-service-provider
predicates:
- name: Path
args:
patterns: [/member/provider/**]
filters:
- name: AddRequestParameter
args:
name: name
value: zzw
- name: AddRequestHeader
args:
name: token
value: 123456
- name: AddResponseHeader
args:
name: Cache-Control
value: no-cache
自定义GlobalFilter
需求
1.自定义全局GlobalFilter过滤器
2.如果有请求参数 user=zzw,password=123456就放行,否则不能通过验证。
实现
1.创建自定义GlobalFiltersrc/main/java/com/zzw/springcloud/filter/CustomGatewayFilter.java
实现接口:需要同时实现GlobalFilter和Ordered两个接口
核心方法:
filter():包含主要过滤逻辑
getOrder():控制过滤器执行顺序
执行顺序:数字越小优先级越高,设置为0表示最高优先级
参数处理:使用getFirst()方法获取参数第一个值,适用于单值参数场景
示例URL:http://localhost:20000/member/get/1?user=hspedu&pwd=123456
@Slf4j
@Component
public class CustomGatewayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//http://localhost:20000/member/provider/selectById/1?user=zzw&pwd=123456
//使用ServerWebExchange获取请求参数,通过getQueryParameters()和getFirst()方法提取特定参数
String user = exchange.getRequest().getQueryParams().getFirst("user");
String pwd = exchange.getRequest().getQueryParams().getFirst("pwd");
log.info("user: {}, pwd: {}", user, pwd);
if (!"zzw".equals(user) || !"123456".equals(pwd)) {
//不满足条件返回406状态码,该状态码表示客户端发送的请求不被服务器接受,用于告知客户端请求存在问题。
//设置状态码:HttpStatus.NOT_ACCEPTABLE
//结束响应:exchange.getResponse().setComplete()
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
//放行条件:当参数验证通过时
//实现方式:调用chain.filter(exchange)将请求传递到下一个过滤器或服务
//链式处理:Gateway支持多个过滤器形成执行链,通过Ordered接口控制执行顺序
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
2.测试…
自定义 GlobalFilter:请求验证与拦截实践指南
《Spring Cloud Gateway 全局过滤器与内置过滤器的对比》