当前位置: 首页 > news >正文

网关过滤器使用及其原理分析

1.网关过滤器介绍

网关过滤器的用途一般是修改请求或响应信息,例如编解码、Token验证、流量复制等

官方文档地址:Spring Cloud Gateway

网关过滤器分为GloablFilter、GatewayFilter及DefaultFilter

过滤器的执行顺序由Order决定,Order值越小,优先级越高,越先执行

1.1 GlobalFilter

自定义的GlobalFilter一般需要实现GlobalFilter和Order接口,官网的示例代码如下:

@Bean
public GlobalFilter customFilter() {return new CustomGlobalFilter();
}@Slf4j
@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info("custom global filter");return chain.filter(exchange);}@Overridepublic int getOrder() {return -1;}
}

配置了全局过滤器之后,当接收到匹配路由的请求时,会执行过滤

1.2 DefaultFilter

DefaultFilter也可以作用于所有路由,配置方式如下:

spring:cloud:gateway:default-filters:- AddRequestHeader=X-Request-Id,123456

1.3 GatewayFilter

官方提供了许多现成的GatewayFilter,可以直接使用,具体参考官方文档,RewritePath示例如下:

spring:cloud:gateway:routes:- id: rewritepath_routeuri: https://example.orgpredicates:- Path=/red/**filters:- RewritePath=/red/?(?<segment>.*), /$\{segment}

很多场景下需要自定义GatewayFilter,一般可以自定义GatewayFilterFactory继承自AbstractGatewayFilterFactory,名称必须由filter名称+GatewayFilterFactory组成,然后再实现apply方法中返回自定义的GatewayFilter对象,该对象一般需要实现GatewayFilter及Order接口,示例如下:

@Component
public class CustomGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomConfig> {public CustomGatewayFilterFactory() {super(CustomConfig.class);}@Overridepublic GatewayFilter apply(CustomConfig config) {return new CustomGatewayFilter(config);}
}
@Getter
@Setter
public class CustomConfig {private String desc;
}
@Slf4j
public class CustomGatewayFilter implements GatewayFilter, Ordered {// 配置类,对应yaml中的args部分private CustomConfig config;public CallbackGatewayFilter(CallbackConfig config) {this.config = config;}@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 执行过滤逻辑log.info("custom gateway filter:{}", config.getDesc);return chain.filter(exchange);}@Overridepublic int getOrder() {return 0;}
}

在配置文件中使用时,通过name属性指定filter名称,可以通过args传入自定义配置参数,这些参数会被封装到配置类CustomConfig中,例如:

spring:cloud:gateway:routes:- id: oldServeruri: lb://oldServerpredicates:- Path=/MyServer/**filters:# 通过name+GatewayFilterFactory找到对应的过滤器- name: Custom# 自定义过滤器配置args:desc: "this is a custom filter"

2.实际开发中的应用

2.1 缓存请求体全局过滤器

添加缓存请求体的全局过滤器,作用是避免后续获取body数据时报错Only one connection receive subscriber allowed,因为原始的body数据只能被订阅读取一次

@Slf4j
@Component
public class CacheRequestBodyGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();HttpHeaders headers = request.getHeaders();long contentLength = headers.getContentLength();Optional<String> chunked = headers.toSingleValueMap().entrySet().stream().filter(entry -> entry.getKey().equalsIgnoreCase(HttpHeaders.TRANSFER_ENCODING.toLowerCase())).map(Map.Entry::getValue).filter(value -> value.equalsIgnoreCase("chunked")).findFirst();if (contentLength > 0 || chunked.isPresent()) {return readBody(exchange, chain);}return filterExchange(exchange, chain);}private Mono<Void> readBody(ServerWebExchange exchange, GatewayFilterChain chain) {return DataBufferUtils.join(exchange.getRequest().getBody()).flatMap(dataBuffer -> {byte[] bytes = new byte[dataBuffer.readableByteCount()];dataBuffer.read(bytes);DataBufferUtils.release(dataBuffer);// Flux.defer()延迟创建Flux,直到有订阅者时才创建Flux<DataBuffer> cachedFlux = Flux.defer(() -> {DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);// 添加到exchange的requestBody属性中exchange.getAttributes().put("requestBody", new String(bytes));return Mono.just(buffer);});// 构建ServerHttpRequest的装饰器,重写getBody方法,避免出现body只能获取一次的问题ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {@Overridepublic Flux<DataBuffer> getBody() {return cachedFlux;}};// 修改exchange中的请求对象ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build();return filterExchange(mutatedExchange, chain);});}@Overridepublic int getOrder() {// 最高优先级return HIGHEST_PRECEDENCE;}private static Mono<Void> filterExchange(ServerWebExchange exchange, GatewayFilterChain chain) {return ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders()).bodyToMono(String.class).doOnNext(objectValue -> log.info("[GatewayContext]Read body Success")).then(chain.filter(exchange));}
}

2.2 请求加解密过滤器

在实际开发中,网关接收到的请求内容时常是加密的,需要解密,而响应的内容有时需要加密,这种场景下可以通过自定义网关过滤器实现

1)创建加解密过滤器工厂类

@Component
public class EncryptDecryptGatewayFilterFactory extends AbstractGatewayFilterFactory<EncryptDecryptConfig> {public EncryptDecryptGatewayFilterFactory() {super(EncryptDecryptConfig.class);}@Overridepublic GatewayFilter apply(EncryptDecryptConfig config) {return new EncryptDecryptFilter(config);}
}

2)创建加解密过滤器

@Slf4j
public class EncryptDecryptFilter implements GatewayFilter, Ordered {private final EncryptDecryptConfig config;public EncryptDecryptFilter(EncryptDecryptConfig config) {this.config = config;}@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 创建一个表达式对象ExchangeExpression expression = new ExchangeExpression(exchange);// 如果没有配置待解密表达式,则无需解密List<String> encodedFieldList = config.getEncodedField();if (!CollectionUtils.isEmpty(encodedFieldList)) {String encodeData = null;for (String encodedField : encodedFieldList) {// 执行表达式,获取待解密的字符串encodeData = (String) expression.evalNoException(encodedField);if (!StringUtils.isEmpty(encodeData)){break;}}String bodyData;if (StringUtils.hasText(encodeData)) {// 执行解密,这里使用最简单的Base64进行加解密,可以根据实际情况换成其他的加解密算法,这里仅演示网关的作用bodyData = Base64.decodeStr(encodeData);// 假设请求体是JSON格式,获取解密后的内容,设置到上下文中,这样后面的过滤器可以方便使用Map<String, Object> bodyMap = JSONUtil.parseObj(bodyData);for (Map.Entry<String, Object> entry : bodyMap.entrySet()) {exchange.getAttributes().put(entry.getKey(), entry.getValue());}// 重新构造解密后的exchange内容ExchangeConfig exchangeConfig = ExchangeConfig.builder().bodyObject(bodyData).bodyContentType(config.getRequestContentType()).header((Map<String, String>) expression.getField("header")).param((Map<String, String>) expression.getField("param")).build();exchange = ServerWebExchangeUtil.rebuildRequest(exchange, exchangeConfig);}}// 根据配置判断响应是否需要加密boolean encrypt = Boolean.TRUE.equals(config.getCrypt());if (encrypt) {// 如果需要加密,则修改响应内容return chain.filter(exchange.mutate().response(buildResponse(exchange)).build());}// 执行下一个过滤器return chain.filter(exchange);}@Overridepublic int getOrder() {// 设置过滤器执行顺序,解密过滤器一般优先级最高,order必须小于-1,否则writeWith方法不生效,原因是NettyWriteResponseFilter的order为-1return config.getOrder() == null ? Integer.MIN_VALUE + 1 : config.getOrder();}private ServerHttpResponseDecorator buildResponse(ServerWebExchange exchange) {ServerHttpResponse originalResponse = exchange.getResponse();return new ServerHttpResponseDecorator(originalResponse) {@Overridepublic HttpHeaders getHeaders() {HttpHeaders headers = super.getHeaders();

相关文章:

网关过滤器使用及其原理分析

1.网关过滤器介绍 网关过滤器的用途一般是修改请求或响应信息,例如编解码、Token验证、流量复制等 官方文档地址:Spring Cloud Gateway 网关过滤器分为GloablFilter、GatewayFilter及DefaultFilter 过滤器的执行顺序由Order决定,Order值越小,优先级越高,越先执行 1.1…...

jiebaNET中文分词器

最近我接手了一个有趣的需求&#xff0c;需要对用户评价进行分词&#xff0c;进行词频统计和情绪分析&#xff0c;并且根据词频权重制成词云图以供后台数据统计&#xff0c;于是我便引入了jieba分词器,但是我发现网上关于jiebaNET相关文档实在太少了&#xff0c;甚至连配置文件…...

springboot3项目练习详细步骤(第四部分:文件上传、登录优化、多环境开发)

目录 本地文件上传 接口文档 业务实现 登录优化 SpringBoot集成redis 实现令牌主动失效机制 多环境开发 本地文件上传 接口文档 业务实现 创建FileUploadController类并编写请求方法 RestController public class FileUploadController {PostMapping("/upload&…...

视觉里程计的融合方法及优缺点分析

视觉里程计是视觉slam的一部分&#xff0c;即前端部分&#xff0c;用于前端跟踪并建立局部地图。多用于重定位或辅助定位&#xff0c;常用的有特征点法&#xff0c;光流法和直接法&#xff0c;其区别和优缺点如下。 特征点法&#xff0c;需要计算特征点和描述子&#xff0c;计算…...

SQL常用基础语句(一)-- FGHIJ开头

GROUP BY GROUP BY语法可以根据给定数据列的每个成员对查询结果进行分组统计&#xff0c;最终得到一个分组汇总表。在GROUP BY子句后面包含了一个HAVING子句&#xff0c;HAVING类似于WHERE&#xff0c;&#xff08;唯一的差别是WHERE过滤行&#xff0c;HAVING过滤组&#xff0…...

大语言模型量化方法对比:GPTQ、GGUF、AWQ 包括显存和速度

GPTQ: Post-Training Quantization for GPT Models GPTQ是一种4位量化的训练后量化(PTQ)方法&#xff0c;主要关注GPU推理和性能。 该方法背后的思想是&#xff0c;尝试通过最小化该权重的均方误差将所有权重压缩到4位。在推理过程中&#xff0c;它将动态地将其权重去量化为f…...

实现本地访问云主机,以及在云主机搭建FTP站点

前言 云计算是一种基于互联网的计算模式&#xff0c;通过网络提供按需访问的计算资源和服务。核心概念是把计算能力视作一种公共资源&#xff0c;用户可以根据自身需求动态分配和管理这些资源。 云主机 ECS (Elastic Compute Server)是一种按需获取的云端服务器&#xff0c;提…...

存储+调优:存储-Cloud

存储调优&#xff1a;存储-Cloud Master Server 配置&#xff1a; IP192.168.1.254 useradd mfs tar zxf mfs-1.6.11.tar.gz.gz cd mfs-1.6.11 ./configure --prefix/usr --sysconfdir/etc --localstatedir/var/lib --with-default-usermfs --with-default-groupmfs --disabl…...

海山数据库(He3DB)线程池方案详解

前言 对于应用开发人员来说肯定听说过连接池&#xff0c;却不一定听说过线程池&#xff0c;虽然二者都是池化的概念&#xff0c;但还是有所不同的&#xff1a; 连接池面向的是数据库连接&#xff0c;是针对数据库Client侧的优化。连接池可将数据库连接数固定在一定范围内&#…...

K8s 高级调度

文章目录 K8s 高级调度CronJobinitContainerTaint 和 Toleration污点&#xff08;Taint&#xff09;容忍&#xff08;Toleration&#xff09; AffinityNodeAffinityPodAnffinity 和 PodAntiAffinity 总结 K8s 高级调度 CronJob 在 k8s 中周期性运行计划任务&#xff0c;与 li…...

数据猿携手IDC Directions 2024:探索中国ICT市场新趋势

大数据产业创新服务媒体 ——聚焦数据 改变商业 近日&#xff0c;ICT业界人士、行业数字化专家&#xff0c;以及来自投资机构、协会、智库的近500位嘉宾聚首北京&#xff0c;参加了IDC Directions 2024&#xff1a;中国ICT市场趋势论坛&#xff08;北京站&#xff09;活动。活…...

前端开发工程师——ajax

express框架 终端输入 npm init --yes npm i express 请求报文/响应报文 // 1.引入express const express require(express);// 2.创建应用对象 const app express();// 3.创建路由规则 // request:是对请求报文的封装 // response&#xff1a;是对响应报文的封装 app.get(…...

uni-app项目在微信开发者工具打开时报错[ app.json 文件内容错误] app.json: 在项目根目录未找到 app.json

uni-app项目在微信开发者工具打开时报错[ app.json 文件内容错误] app.json: 在项目根目录未找到 app.json 出现这个问题是因为打开的文件地址不对&#xff0c;解决这个问题首先我们要查看是否有unpackage文件夹&#xff0c;如果有&#xff0c;项目直接指向unpackage\dist\dev\…...

最大连续1的个数(滑动窗口)

算法原理&#xff1a; 这道题大眼一看是关于翻转多少个0的问题&#xff0c;但是&#xff0c;如果你按照这种思维去做题&#xff0c;肯定不容易。所以我们要换一种思维去做&#xff0c;这种思维不是一下就能想到的&#xff0c;所以想不到也情有可原。 题目是&#xff1a;给定一…...

Spring Cloud 框架的应用详解

Spring Cloud 框架的应用详解 Spring Cloud 是一个基于 Spring Boot 的微服务架构开发工具&#xff0c;它提供了一系列工具用于快速构建分布式系统中的常见模式&#xff0c;如配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、选举、分布式会话和集群状态管理…...

C语言 数组——向函数传递数组

目录 把数组传给函数&#xff08;Passing Arrays to Functions&#xff09; 向函数传递一维数组 向函数传递二维数组 数组在学生成绩管理中的应用 例&#xff1a;计算每个学生的平均分 把数组传给函数&#xff08;Passing Arrays to Functions&#xff09; 向函数传递一维…...

数据链路层简单介绍

mac地址&#xff08;物理地址&#xff09; mac地址和ip地址&#xff0c;目的都是为了区分网络上的不同设备的&#xff0c;在最开始的时候&#xff0c;mac地址和ip地址是两伙人&#xff0c;独立各自提出的&#xff0c;ip地址是4个字节&#xff08;早都不够用了&#xff09;&…...

【软考】设计模式之装饰器模式

目录 1. 说明2. 应用场景3. 结构图4. 构成5. 适用性6. 优点7. 缺点8. java示例 1. 说明 1.动态地给一个对象添加一些额外的职责。2.Decorator Pattern。3.就增加功能而言&#xff0c;装饰器模式比生成子类更加灵活。4.一种在不改变现有对象结构的情况下&#xff0c;动态地给对…...

网络编程day6

IO多路复用的原理 IO多路复用是一种通过同时监视多个文件描述符&#xff08;通常是套接字&#xff09;来处理多个I/O操作的机制。它的原理可以简单概括为&#xff1a; 单线程处理多个I/O操作&#xff1a;传统的I/O模型中&#xff0c;每个I/O操作都需要一个线程或进程来处理。而…...

5.23总结

新增功能点 讨论 学生和老师均可发布话题&#xff0c;话题发布后&#xff0c;在该课程的用户可以在发布话题的课程中点击讨论参与课程的讨论&#xff0c;并可以进行评论&#xff0c;回复评论&#xff0c;点赞操作。每个话题发布时可添加多个图片文件&#xff0c;参加讨论的话…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

Webpack性能优化:构建速度与体积优化策略

一、构建速度优化 1、​​升级Webpack和Node.js​​ ​​优化效果​​&#xff1a;Webpack 4比Webpack 3构建时间降低60%-98%。​​原因​​&#xff1a; V8引擎优化&#xff08;for of替代forEach、Map/Set替代Object&#xff09;。默认使用更快的md4哈希算法。AST直接从Loa…...

高效的后台管理系统——可进行二次开发

随着互联网技术的迅猛发展&#xff0c;企业的数字化管理变得愈加重要。后台管理系统作为数据存储与业务管理的核心&#xff0c;成为了现代企业不可或缺的一部分。今天我们要介绍的是一款名为 若依后台管理框架 的系统&#xff0c;它不仅支持跨平台应用&#xff0c;还能提供丰富…...

【java】【服务器】线程上下文丢失 是指什么

目录 ■前言 ■正文开始 线程上下文的核心组成部分 为什么会出现上下文丢失&#xff1f; 直观示例说明 为什么上下文如此重要&#xff1f; 解决上下文丢失的关键 总结 ■如果我想在servlet中使用线程&#xff0c;代码应该如何实现 推荐方案&#xff1a;使用 ManagedE…...