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

记一次线上bug排查-----SpringCloud Gateway组件 请求头accept-encoding导致响应结果乱码

       基于公司的业务需求,在SpringCloud Gateway组件的基础上,写了一个转发服务,测试开发阶段运行正常,并实现初步使用。但三个月后,PostMan请求接口,返回异常,经排查,从日志中获取到转发响应的结果为乱码:

      

跟踪日志:

转发到目标接口,响应结果已乱码。一般排查的思路是,查看请求方和响应方的编码格式是否一致,打印请求方的编码格式为UTF-8,响应服务的编码格式也是UTF-8。

以上说明编码格式没有问题。上网去找“gateway响应结果乱码”的相关文章,大多数会提供解决方案:

DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
DataBuffer join = dataBufferFactory.join(dataBuffers);
byte[] content = new byte[join.readableByteCount()];
join.read(content);
// 释放掉内存
DataBufferUtils.release(join);
String str = new String(content, Charset.forName("UTF-8"));
originalResponse.getHeaders().setContentLength(str.getBytes().length);
System.out.println(str);
return bufferFactory.wrap(str.getBytes());

这段关键代码,在我的响应结果包装过滤器是有的,如下:

    /*** 获取到解码方的response,验签--->重新封装--->加签* 通过 DataBufferFactory 解决响应体分段传输问题。*/private ServerHttpResponseDecorator verifyRePackageSignatureResponse(ServerWebExchange exchange, String jmf_decode_url, String route_privateKey, String jmf_publicKey) {ServerHttpResponse response = exchange.getResponse();log.debug("R:给响应结果response设置编码格式----START----");response.getHeaders().add("Content-Type","application/json;charset=UTF-8");log.debug("R:给响应结果response设置编码格式-----END-----");DataBufferFactory bufferFactory = response.bufferFactory();return new ServerHttpResponseDecorator(response) {@Overridepublic Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {if (body instanceof Flux) {// 获取响应类型,如果是 json 就打印String originalResponseContentType = exchange.getAttribute(ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);log.debug("响应类型为originalResponseContentType:{}",originalResponseContentType);if (RequestResponseUtil.isJson(originalResponseContentType)) {Flux<? extends DataBuffer> fluxBody = Flux.from(body);return super.writeWith(fluxBody.buffer().map(dataBuffers -> {// 合并多个流集合,解决返回体分段传输DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();DataBuffer join = dataBufferFactory.join(dataBuffers);byte[] content = new byte[join.readableByteCount()];join.read(content);// 释放掉内存DataBufferUtils.release(join);// 正常返回的数据String rootData = new String(content, StandardCharsets.UTF_8);log.debug("R:正常返回的数据rootData为:{}", rootData);//使用枚举 + 工厂 + 策略模式(第二版)String newQqtBodyJson = null;try {newQqtBodyJson = DecoderSignStrategyContext.zwmVerifySignResponse(rootData, jmf_decode_url, route_privateKey, jmf_publicKey);log.debug("R:【码路由服务】经具体策略处理,得到结果newQqtBodyJson为:{}", newQqtBodyJson);} catch (Exception e) {log.error("R:【码路由服务】解码方返回结果验签异常:{}", e);throw new VerifySignException(StaticVar.FAIL_10020015, "R:【码路由服务】解码方返回结果验签异常");}byte[] respData = newQqtBodyJson.getBytes();//byte[] respData = newQqtBodyJson.getBytes(StandardCharsets.UTF_8);byte[] uppedContent = new String(respData, Charset.forName("UTF-8")).getBytes();return bufferFactory.wrap(uppedContent);}));} else {log.error("响应结果异常");throw new ProcessHandleException(StaticVar.FAIL_10020015, "R:【码路由服务】解码方返回结果异常,非法JSON");}}// if body is not a flux. never got there.return super.writeWith(body);}};}

因此不是代码的问题。又找到了一篇文章,解决了PostMan请求的问题。

https://bbs.csdn.net/topics/399102026/close

如上所述,在PostMan请求的headers中去掉Accept-Encoding,请求成功:

       至此,PostMan请求乱码的问题已解决。但事情似乎没有那么简单,接下来,使用手机模拟扫码,请求码路由服务,又出现了乱码,扫码结果页面,返回结果:

 查看日志,乱码如下:

      排查问题进入瓶颈期,有些烦躁了,必须冷静下来,重新捋一下代码,同时也在想,既然和PostMan请求存在同样的问题,是不是在请求头中默认会有一个Accept-Encoding属性,从而导致了乱码,根据这个思路,在自定义的请求转发过滤器中,发现了以下代码:

由于在请求转发的逻辑中,重新构建了一个request请求的同时,重新创建了一个请求头headers,它在重新构建的时候默认会有一个accept-encoding属性,看到这一行代码时,正印证了以上我的猜想,问题已经找到了,将其置为空字符串即可(注意:不能使其为null,也不能remove这个属性,会报错)。

  将headers的accept-encoding属性置为空字符串,并添加注释如下:

// 定义新的消息头HttpHeaders headers = new HttpHeaders();//System.out.println("headers = " + headers); //查看重新定义消息头的内容headers.putAll(exchange.getRequest().getHeaders());// 由于修改了传递参数,需要重新设置CONTENT_LENGTH,长度是字节长度,不是字符串长度int length = bodyStr.getBytes().length;log.debug("bodyStr长度为:{}",length);headers.remove(HttpHeaders.CONTENT_LENGTH);// 设置CONTENT_TYPEif (StringUtils.isNotBlank(contentType)) {headers.set(HttpHeaders.CONTENT_TYPE, contentType);}String jmf_decode_url = request.getURI().toString();String qqtBodyJsonStr = JSONUtils.toString(bizPackage);//request.mutate().header(HttpHeaders.CONTENT_LENGTH, Integer.toString(bodyStr.length())); //报错JSON parse error JsonEOFException,长度必须为字节的长度request.mutate().header(HttpHeaders.CONTENT_LENGTH, Integer.toString(length));//成功,解决JSON parse error JsonEOFException/*** 乱码现象:请求响应结果乱码* 解决过程分为PostMan请求和手机端App扫码请求:*   (1)、PostMan请求响应乱码解决:*             PostMan请求的headers中默认会有"Accept-Encoding"属性,值为"gzip, deflate, br",导致响应结果乱码*         去掉Accept-Encoding后请求正常。**   (2)、手机端App扫码请求乱码解决:*             在HttpRequestSignForwardGatewayFilter中定义新的消息头,headers中默认会有"accept-encoding"属性,*         值为"gzip, deflate, br", 添加代码"request.mutate().header("accept-encoding",""); "解决乱码**       注意: 创建headers对象默认会生成“accept-encoding=‘gzip, deflate, br‘ ”属性,此处必须将accept-encoding*       置为空字符串(置为null会报错),否则使用默认值会导致响应结果乱码。*       说明: 测试开发阶段未发生此问题,第三方检测时演示出现此问题,这个可能是gateway内部的问题,尚未可知。**          经测试,这种方式已解决了:手机端APP扫码和PostMan响应结果乱码的问题(PostMan请求时可以不用刻意去掉Accept-Encoding,*       也可请求成功)**/request.mutate().header("accept-encoding","");

重启后,部署后问题得到解决。这个问题在测试开发阶段没有暴露出来,按理说应该早暴露了,但现实情况就是这么诡异,这可能是Gateway内部的bug,尚未可知。

     希望此文对遇到同样问题的小伙伴有所帮助和启发,望了解gateway内部原理机制的大神,参与讨论。

    乱码问题已排查并处理结束,完结,撒花!

参考文章:

RestTemplate请求头accept-encoding导致乱码_resttemplate 乱码_AE86Jag的博客-CSDN博客

https://bbs.csdn.net/topics/399102026/close

在此感谢文章作者!

相关文章:

记一次线上bug排查-----SpringCloud Gateway组件 请求头accept-encoding导致响应结果乱码

基于公司的业务需求&#xff0c;在SpringCloud Gateway组件的基础上&#xff0c;写了一个转发服务&#xff0c;测试开发阶段运行正常&#xff0c;并实现初步使用。但三个月后&#xff0c;PostMan请求接口&#xff0c;返回异常&#xff0c;经排查&#xff0c;从日志中获取到转发…...

复杂数据统计与R语言程序设计实验一

1.下载并安装R语言软件&#xff0c;熟悉基本操作的命令及操作界面&#xff0c;掌握软件的使用方法&#xff08;提供学号加姓名的截图&#xff09;。 2.下载并安装Rstudio&#xff0c; &#xff08;提供运行代码及运行结果的截图&#xff09;。 3.下载并安装R包DT&#xff0c;…...

UEFI实战——键盘操作

一、键盘操作 UEFI下如何获取键盘键值,用户输入按键方式分两种:一种是单个按键,另外一种是组合按键。两种方式对应两个Protocol服务,接下来分步讲解。 二、单个按键 单个按键使用Protocol服务是EFI_SIMPLE_TEXT_INPUT_PROTOCOL,它定义在MdePkg/Include/Protocol/Simple…...

苹果CMS首涂第30套可装修DIY主题模板免授权版

这是一款可以装修的主题&#xff0c;类似淘宝店装修一样&#xff0c;可以针对首页、栏目页、详情页、播放页进行自定义装修&#xff0c;内置10个模块自由选择、添加、修改、删除、排序操作&#xff0c;后续升级还会增加更多实用和个性模块供选择&#xff0c;主题内包含的导航、…...

C#每天复习一个重要小知识day2:有参与无参构造函数

using System;public class MyClass {private int value;// 有参构造函数public MyClass(int v){this.value v;}// 无参构造函数public MyClass(){this.value 0;}public static void Main(string[] args){// 使用有参构造函数实例化对象MyClass obj1 new MyClass(10);Consol…...

大语言模型的三阶段训练

为了训练专有领域模型&#xff0c;选择LLaMA2-7B作为基座模型&#xff0c;由于LLaMA模型中文词表有限&#xff0c;因此首先进行中文词表的扩展&#xff0c;然后进行三阶段训练&#xff08;增量预训练&#xff0c;有监督微调&#xff0c;强化学习&#xff09;。 代码将全部上传…...

面试题c/c++ --STL 算法与数据结构

1.6 STL 模板 模板底层实现&#xff1a;编译器会对函数模板进行两次编译&#xff0c; 在声明的地方对模板代码本身进行编译&#xff0c; 在调用的地方对参数替换后的代码进行编译。 模板传参分析 模板重载 vector 是动态空间&#xff0c; 随着元素的加入&#xff0c; 它的内…...

云原生微服务-理论篇

文章目录 分布式应用的需求分布式架构治理模式演进ESB 是什么&#xff1f;微服务架构 MSA微服务实践细节微服务治理框架sidercar 什么是service mesh&#xff1f;康威定律微服务的扩展性什么是MSA 架构&#xff1f;中台战略和微服务微服务总体架构组件微服务网关服务发现与路由…...

Unity模拟薄膜干涉效果

Unity制作薄膜干涉效果&#xff0c;色彩斑斓的黑色石头 大家好&#xff0c;我是阿赵。   这次来做一个模拟薄膜干涉的彩色效果&#xff0c;Shader是使用ASE来连接&#xff0c;也算是ASE做复杂一点的效果的一个例子吧。 一、什么是薄膜干涉 以下解释来源于百度百科&#xff1…...

AIGC ChatGPT4对Gbase数据库进行总结

ChatGPT4 用一个Prompt完成Gbase数据库的总结。 AIGC ChatGPT 职场案例 AI 绘画 与 短视频制作 PowerBI 商业智能 68集 数据库Mysql 8.0 54集 数据库Oracle 21C 142集 Office 2021实战应用 Python 数据分析实战&#xff0c; ETL Informatica 数据仓库案例实战 Excel 2021实操 …...

OSI网络模型与TCP/IP协议

OSI&#xff0c; Open system Interconnection Reference Model 开放式系统互联通信参考模型。是国际标准化组织在1984年定义的一个概念框架&#xff0c;用于协调制定进程间通信标准。OSI作为一个协议规范集&#xff0c;定义了七个层次&#xff0c;包括层次之间的相互关系及各层…...

C语言的5个内存段你了解吗?( 代码段/数据段/栈/堆)

前言&#xff1a;这些内存段在程序运行时起着不同的作用&#xff0c;有不同的分配方式和存储内容。对于 C 语言程序员来说&#xff0c;了解这些内存段的特性和用途有助于更好地理解内存管理、变量的存储位置以及程序执行过程中的内存分配情况 1. 代码段 (Code Segment) 内容&a…...

智能合约检测:新一代区块链技术的安全守护

目录 1、智能合约检测:新一代区块链技术的安全守护 2、智能合约性能检测步骤...

Flutter笔记:缩放手势

Flutter笔记 缩放手势 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/134485138 目 录 1. 概述2. 缩放手…...

JAXB:用XmlElement注解复杂类型的Java属性,来产生多层嵌套的xml元素

例如&#xff0c;下面这段请求的xml代码&#xff0c;在元素body下面又多了一层&#xff0c;嵌套了4个元素&#xff1a; <?xml version"1.0" encoding"UTF-8"?><request><reqtype>04</reqtype><secret>test</secret>…...

万字长文 - Python 日志记录器logging 百科全书 - 高级配置之 日志分层

万字长文 - Python 日志记录器logging 百科全书 - 高级配置之 日志分层 前言 在 Python 的logging模块中&#xff0c;它不仅提供了基础的日志功能&#xff0c;还拥有一系列高级配置选项来满足复杂应用的日志管理需求。 说到logging 模块的高级配置&#xff0c;必须提及日志分…...

工作记录---为什么双11当天不能申请退款?(有趣~)

为什么&#xff1f; 服务降级了 服务降级&#xff1a; 当服务器压力剧增的情况下&#xff0c;根据实际业务情况及流量&#xff0c;对一些服务和页面有策略的不处理或换种简单的方式处理&#xff0c;从而释放服务器资源以保证核心交易正常运作或高效运作。 分布式系统的降级…...

ElasticSearch在Windows上的下载与安装

Elasticsearch是一个开源的分布式搜索和分析引擎&#xff0c;它可以帮助我们快速地搜索、分析和处理大量数据。Elasticsearch能够快速地处理结构化和非结构化数据&#xff0c;支持全文检索、地理位置搜索、自动补全、聚合分析等功能&#xff0c;能够承载各种类型的应用&#xf…...

软件测试/测试开发/人工智能丨基于Spark的分布式造数工具:加速大规模测试数据构建

随着软件开发规模的扩大&#xff0c;测试数据的构建变得越来越复杂&#xff0c;传统的造数方法难以应对大规模数据需求。本文将介绍如何使用Apache Spark构建分布式造数工具&#xff0c;以提升测试数据构建的效率和规模。 为什么选择Spark&#xff1f; 分布式计算&#xff1a;…...

ClickHouse的 MaterializeMySQL引擎

1 概述 MySQL 的用户群体很大&#xff0c;为了能够增强数据的实时性&#xff0c;很多解决方案会利用 binlog 将数据写入到 ClickHouse。为了能够监听 binlog 事件&#xff0c;我们需要用到类似 canal 这样的第三方中间件&#xff0c;这无疑增加了系统的复杂度。 ClickHouse 20.…...

Ubuntu 22.04安装Rust编译环境并且测试

我参考的博客是《Rust使用国内Crates 源、 rustup源 |字节跳动新的 Rust 镜像源以及安装rust》 lsb_release -r看到操作系统版本是22.04,uname -r看到内核版本是uname -r。 sudo apt install -y gcc先安装gcc&#xff0c;要是结果给我的一样的话&#xff0c;那么就是安装好了…...

制作Go程序的Docker容器(以及容器和主机的网络问题)

今天突然遇到需要将 Go 程序制作成 Docker 的需求&#xff0c;所以进行了一些研究。方法很简单&#xff0c;但是官方文档和教程有些需要注意的地方&#xff0c;所以写本文进行记录。 源程序 首先介绍一下示例程序&#xff0c;示例程序是一个 HTTP 服务器&#xff0c;会显示si…...

mysql清除数据痕迹_MySQL使用痕迹清理~/.mysql_history - milantgh

mysql会给出我们最近执行的SQL命令和脚本&#xff1b;同linux command保存在~/.bash_history一样&#xff0c;你用mysql连接MySQL server的所有操作也会被记录到~/.mysql_history文件中&#xff0c;这样就会有很大的安全风险了&#xff0c;如添加MySQL用户的sql也同样会被明文记…...

PDF控件Spire.PDF for .NET【转换】演示:自定义宽度、高度将 PDF 转 SVG

我们在上一篇文章中演示了如何将 PDF 页面转换为 SVG 文件格式。本指南向您展示如何使用最新版本的 Spire.PDF 以及 C# 和 VB.NET 指定输出文件的宽度和高度。 Spire.Doc 是一款专门对 Word 文档进行操作的 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻…...

01背包 P1507 NASA的食物计划

P1507 NASA的食物计划 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 普通01背包状态表示&#xff1a;f(i, j)表示前i件物品放入一个容量为j的背包可以获得的最大价值。 本题类似&#xff0c;f(i, j, k)表示前i件物品放入一个限制为j&#xff0c;且另一个限制为k的背包中可以…...

平衡二叉树c语言版

一、定义二叉树结点结构体 /*** 定义平衡二叉树结点 */ struct avlbinarytree { //数据域NodeData* data;///树高int h;struct avlbinarytree* left;struct avlbinarytree* right; }; typedef struct avlbinarytree AVLNode; 二、声明函数的操作 /*** 创建结点 */ AV…...

初始环境配置

目录 一、JDK1、简介2、配置步骤 二、Redis1、简介2、配置步骤 三、MySQL1、简介2、配置步骤 四、Git1、简介2、配置步骤 五、NodeJS1、简介2、配置步骤 六、Maven1、简介2、配置步骤 七、Tomcat1、简介2、配置步骤 一、JDK 1、简介 JDK 是 Oracle 提供的 Java 开发工具包&…...

记GitLab服务器迁移后SSH访问无法生效的问题解决过程

公司IT心血来潮对GitLab服务器进行安全升级&#xff0c;升级后无法启动。。。只得启用备用服务器&#xff0c;具体的备份机制不祥&#xff0c;只知道原数据都在&#xff0c;但文件系统是否完全一样不清楚。切换为备用服务器后使用SSH下载代码死活不成功&#xff0c;反复提示需要…...

【NGINX--2】高性能负载均衡

1、HTTP 负载均衡 将负载分发到两台或多台 HTTP 服务器。 在 NGINX 的 HTTP 模块内使用 upstream 代码块对 HTTP 服务器实施负载均衡&#xff1a; upstream backend {server 10.10.12.45:80 weight1;server app.example.com:80 weight2;server spare.example.com:80 backup; …...

Android studio run 手机或者模拟器安装失败,但是生成了debug.apk

错误信息如下&#xff1a;Error Installation did not succeed. The application could not be installed&#xff1a;List of apks 出现中文乱码&#xff1b; 我首先尝试了打包&#xff0c;能正常安装&#xff0c;再次尝试了debug的安装包&#xff0c;也正常安装&#xff1…...