SpringCloud Gateway 网关的请求体body的读取和修改
SpringCloud Gateway 网关的请求体body的读取和修改
getway需要多次对body 进行操作,需要对body 进行缓存
缓存body 动态多次获取
新建顶层filter,对body 进行缓存
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.util.List;/*** @author: zhoumo* @descriptions:*/
@Component
@Slf4j
public class RequestParamGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {/*** save request path and serviceId into gateway context*/ServerHttpRequest request = exchange.getRequest();HttpHeaders headers = request.getHeaders();// 处理参数MediaType contentType = headers.getContentType();long contentLength = headers.getContentLength();if (contentLength > 0) {return readBody(exchange, chain);}return chain.filter(exchange);}/*** default HttpMessageReader*/private static final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults().messageReaders();/*** ReadJsonBody** @param exchange* @param chain* @return*/private Mono<Void> readBody(ServerWebExchange exchange, GatewayFilterChain chain) {/*** join the body*/return DataBufferUtils.join(exchange.getRequest().getBody()).flatMap(dataBuffer -> {byte[] bytes = new byte[dataBuffer.readableByteCount()];dataBuffer.read(bytes);DataBufferUtils.release(dataBuffer);Flux<DataBuffer> cachedFlux = Flux.defer(() -> {DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);DataBufferUtils.retain(buffer);return Mono.just(buffer);});/*** repackage ServerHttpRequest*/ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {@Overridepublic Flux<DataBuffer> getBody() {return cachedFlux;}};/*** mutate exchage with new ServerHttpRequest*/ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build();/*** read body string with default messageReaders*/return ServerRequest.create(mutatedExchange, messageReaders).bodyToMono(String.class).doOnNext(objectValue -> {log.debug("[GatewayContext]Read JsonBody:{}", objectValue);}).then(chain.filter(mutatedExchange));});}@Overridepublic int getOrder() {return HIGHEST_PRECEDENCE;}
}
在子节点层获取body
AtomicReference<String> requestBody = new AtomicReference<>("");RecorderServerHttpRequestDecorator requestDecorator = new RecorderServerHttpRequestDecorator(request);Flux<DataBuffer> body = requestDecorator.getBody();body.subscribe(buffer -> {CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());requestBody.set(charBuffer.toString());});String body= requestBody.get();
重写获取body方法
public class RecorderServerHttpRequestDecorator extends ServerHttpRequestDecorator {private final List<DataBuffer> dataBuffers = new ArrayList<>();public RecorderServerHttpRequestDecorator(ServerHttpRequest delegate) {super(delegate);super.getBody().map(dataBuffer -> {dataBuffers.add(dataBuffer);return dataBuffer;}).subscribe();}@Overridepublic Flux<DataBuffer> getBody() {return copy();}private Flux<DataBuffer> copy() {return Flux.fromIterable(dataBuffers).map(buf -> buf.factory().wrap(buf.asByteBuffer()));}}
对body 进行修改重新封装
String str=""+encodedDecryptedParam;DataBuffer bodyDataBuffer = stringBuffer(str);Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);MediaType contentType = request.getHeaders().getContentType();ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {@Overridepublic HttpHeaders getHeaders() {HttpHeaders httpHeaders = new HttpHeaders();int length = str.getBytes().length;httpHeaders.putAll(super.getHeaders());httpHeaders.remove(HttpHeaders.CONTENT_TYPE);httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);httpHeaders.setContentLength(length);httpHeaders.set(HttpHeaders.CONTENT_TYPE, contentType.toString());// 设置CONTENT_TYPEreturn httpHeaders;}@Overridepublic Flux<DataBuffer> getBody() {return bodyFlux;}};return chain.filter(exchange.mutate().request(mutatedRequest).build());
protected DataBuffer stringBuffer(String value) {byte[] bytes = value.getBytes(StandardCharsets.UTF_8);NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);buffer.write(bytes);return buffer;}
一定必须加上
public HttpHeaders getHeaders()
对header 重新封装,否则接口层会卡死,request 无限大
相关文章:
SpringCloud Gateway 网关的请求体body的读取和修改
SpringCloud Gateway 网关的请求体body的读取和修改 getway需要多次对body 进行操作,需要对body 进行缓存 缓存body 动态多次获取 新建顶层filter,对body 进行缓存 import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.gateway.filt…...

气膜场馆的降噪方法
在现代社会,噪音已经成为我们生活中难以避免的问题,而气膜场馆也不例外。传统的气膜场馆常常因其特殊结构而面临噪音扩散和回声问题,影响了人们的体验和活动效果。然而,随着科技的进步,多功能声学综合馆应运而生&#…...

探索主题建模:使用LDA分析文本主题
在数据分析和文本挖掘领域,主题建模是一种强大的工具,用于自动发现文本数据中的隐藏主题。Latent Dirichlet Allocation(LDA)是主题建模的一种常用技术。本文将介绍如何使用Python和Gensim库执行LDA主题建模,并探讨主题…...

服务器黑洞,如何秒解
想必这样的短信大家都应该见过吧,这其实是阿里云服务器被攻击后触发的黑洞机制的短信通知。还有很多朋友不知道,为什么要这么做。原因其实很简单啊,当同一个机房的ip段,如果说有一台服务器遭受低道攻击,那么很可能会造…...

【生物信息学】单细胞RNA测序数据分析:计算亲和力矩阵(基于距离、皮尔逊相关系数)及绘制热图(Heatmap)
文章目录 一、实验介绍二、实验环境1. 配置虚拟环境2. 库版本介绍 三、实验内容0. 导入必要的库1. 读取数据集2. 质量控制(可选)3. 基于距离的亲和力矩阵4. 绘制基因表达的Heatmap5. 基于皮尔逊相关系数的亲和力矩阵6. 代码整合 一、实验介绍 计算亲和力…...

学习笔记三十一:k8s安全管理:认证、授权、准入控制概述SA介绍
K8S安全实战篇之RBAC认证授权-v1 k8s安全管理:认证、授权、准入控制概述认证k8s客户端访问apiserver的几种认证方式客户端认证:BearertokenServiceaccountkubeconfig文件 授权Kubernetes的授权是基于插件形成的,其常用的授权插件有以下几种&a…...
【开发新的】apache common BeanUtils忽略null值
前言: BeanUtils默认的populate方法不会忽略空值和null值,在特定场景,我们需要原始的值避免被覆盖,所以这里提供一种自定义实现方式。 package com.hmwl.service.program;import lombok.extern.slf4j.Slf4j; import org.apache.commons.beanu…...

coalesce函数(SQL )
用途: 将控制替换成其他值;返回第一个非空值 表达式 COALESCE是一个函数, (expression_1, expression_2, …,expression_n)依次参考各参数表达式,遇到非null值即停止并返回该值。如果所有的表达式都是空值,最终将返…...

一键报警可视对讲管理机10寸触摸屏管理机
一键报警可视对讲管理机10寸触摸屏管理机 一、管理机技术指标: 1、10寸LCD触摸屏,分辨率1024*600; 2、摄像头1200万像素 3、1000M/100M自适应网口; 4、按键设置:报警/呼叫按键,通话/挂机按键࿰…...
java左右括号
java左右括号 数据结构-栈栈的特点:先进后出代码实现 最近看到有小伙伴去面试,被人问起一道算法题,题目内容大概是:给定一个字符串,如:“[[]]{}”,判断字符串是否为有效的括号。考查的是数据结构…...

接口自动化测试 —— 工具、请求与响应
一、工具: 1.工具介绍 postman :很主流的API测试工具,也是工作里面使用最广泛的研发工具。 JMeter: ApiPost: 2.安装postman: 安装好直接打开,不用注册。 二、通信模式: 1、…...

【LeetCode:2103. 环和杆 | 模拟】
🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…...

微信小程序-授权登录(手机号码)
1、WXBizDataCrypt.js-下载地址 2、UNIAPP代码 <template> <view class"work-container"> <view class"login"> <view class"content"> <button class"button_wx&q…...

视觉问答(VQA)12篇顶会精选论文合集,附常用数据集下载
今天来聊聊计算机视觉和自然语言处理交叉的一个热门研究方向:视觉问答(VQA)。 视觉问答的任务是:给出一张图片和一个关于这张图片的自然语言问题,计算机需要根据图片的内容自动回答这个问题。这样的任务考验了计算机在…...
详解--编码(ASCII\Unicode,UTF-8\UTF-16\UTF-32)
本文主要搞清楚编码是怎么回事。 参考链接 字符集编码方式ASCII(American Standard Code for Information Interchange)ASCIIGB2312GB2312UnicodeUTF-8 / UTF-16 / UTF-32 1.编码基本概念 1.1 字符 字符(Character) 在计算机和…...

Linux安装配置awscli命令行接口工具及其从aws上传下载数据
官网技术文档有全面介绍:安装或更新 AWS CLI 的最新版本 - AWS Command Line Interface在系统上安装 AWS CLI。https://docs.aws.amazon.com/zh_cn/cli/latest/userguide/getting-started-install.html#getting-started-install-instructionsawscli常用命令参考&…...

中国联通携手华为助力长城精工启动商用5G-A柔性产线
[中国,河北,2023年11月3日] 近日,中国联通携手华为助力精诚工科汽车系统有限公司保定自动化技术分公司(简称长城精工自动化)启动5G-A超高可靠性超低时延柔性产线的商用阶段。 在河北保定精工自动化工厂,5G…...

【自动化测试】Java+Selenium自动化测试环境搭建
本主要介绍以Java为基础,搭建Selenium自动化测试环境,并且实现代码编写的过程。 1.Selenium介绍 Selenium 1.0 包含 core、IDE、RC、grid 四部分,selenium 2.0 则是在两位大牛偶遇相互沟通决定把面向对象结构化(OOPP)…...

若依笔记(四):代码生成器
已知使用MyBatisPlus代码生成器可以自动生成Entity、Mapper、Service、Controller代码,前提是数据库中有数据表,生成pojo类以及对于该数据表的增删改查命令的代码,若依更进一步能选择表后生成代码、预览、下载,同时可以生产前端代…...

怎样做好金融投资翻译
我们知道, 金融投资翻译所需的译文往往是会议文献、年终报表、信贷审批等重要企业金融资料,其准确性事关整个企业在今后一段时期内的发展战略与经营成效。尤其像年报,对于上市公司来说更是至关重要的。那么,怎样做好金融投资翻译&…...

19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...