Gateway网关在url参数带有特殊字符的情况下转发失败(响应400)

本文主要分享了,SpringCloud Gateway网关在url参数带有空格或者特殊字符的情况下,转发失败导致响应错误码400的解决方案。

响应400错误码的2种场景:

1.参数带空格,Gateway会误认为该空格是切割符,如?phone= 135****6862&type=44,不能正常解析协议,直接异常

2.参数带特殊字符,如?phone=|135****6862&type=44,能正常解析协议,但转发后异常

一、问题分析

1.可用性<99的问题接口:

质量组反馈的可用性文档中,显示错误码(4xx)特别多,如下图 

2.排查:

根据错误码匹配应用日志,未发现异常日志

根据错误码匹配Gateway网关日志,未发现异常日志

根据错误码匹配nginx日志,发现异常日志(基本都是响应400错误码)

{"clientip": "100.xxx.xxx.250","timestamp": "2024-01-03T00:52:10+08:00","request_method": "POST","response": "400","byte": "131","uri": "/api/xxx/xxx/smsCode","param": "phone= 135****6862&type=44","referrer": "-","agent": "Mozilla/5.0 (Linux; U; Android 4.4.1; zh-cn; R815T Build/JOP40D) AppleWebKit/533.1 (KHTML, like Gecko)Version/4.0 MQQBrowser/4.5 Mobile Safari/533.1","httpx_for": "221.xx.xx.60","http_host": "domain.com","upstream_addr": "172.xxx.xxx.123:8280","request_time": "0.011","upstream_response_time": "0.010","ssl_protocol": "-"
}

3.分析:

是由于请求参数带了空格(phone= 135****6862&type=44)导致(该空格非前端正常传参误操作,是恶意请求),初步怀疑是nginx转发问题,因为网关未找到任何日志。经运维同事协助排查,发现是Gateway网关响应的400错误码,没有日志是因为日志级别没有设置到debug,所以未打印

4.排查与复现:

问题复现测试用例

 

断点排查发现经过代码HttpObjectDecoder.splitInitialLine后将sb内容切割为一个3个元素的数组,切割规则中空格就是其中一个切割符。

注意:这里不能使用hutool http工具请求,因为会对url进行urlencode,无法复现效果

sb样本为:

GET http://localhost:8280/api/xxx/xxx/smsCode?phone= 135****6862 HTTP/1.1

数组样本为:

["GET","http://localhost:8280/api/xxx/xxx/smsCode?phone=","135****6862 HTTP/1.1"]

后续代码中取第三个元素‘135****6862 HTTP/1.1’作为http协议转换导致异常,所以响应400

二、解决方案

1.思路:

想办法改写HttpObjectDecoder.splitInitialLine的逻辑,上述情况数组样本为:

["GET","http://localhost:8280/api/xxx/xxx/smsCode?phone=135****6862","HTTP/1.1"]

2.实现:

经网络资料查询,可以通过以下代码在Netty ChannelPipeline中添加ChannelHandler

经源码分析,ChannelPipeline会有默认的http处理器NettyPipeline.HttpCodec(其实现类为HttpServerCodec),而HttpObjectDecoder.splitInitialLine的逻辑就是通过HttpServerCodec实现类来调用的

所以,想办法替换NettyPipeline.HttpCodec的实现类即可

 

复制框架源码HttpObjectDecoder、HttpRequestDecoder、HttpServerCodec至项目目录中(重命名加前缀Custom),如下图 

将这3个类(Custom*)中用到HttpObjectDecoder、HttpRequestDecoder、HttpServerCodec的地方,全部修改为加Custom前缀的类,如 

修改CustomHttpObjectDecoder.splitInitialLine的逻辑

核心思想:将sb按切割符切割出所有元素,数组组装逻辑改为取第一个、取最后一个、中间部分拼接在一起 

sb样本为:

GET http://localhost:8280/api/xxx/xxx/smsCode?phone= 135****6862 HTTP/1.1

list样本为:

["GET","http://localhost:8280/api/xxx/xxx/smsCode?phone=","135****6862","HTTP/1.1"]

数组样本为:

["GET","http://localhost:8280/api/xxx/xxx/smsCode?phone=135****6862","HTTP/1.1"]

保险起见(非必要逻辑):

1)在异常情况下执行旧逻辑

2)增加开关控制(可通过apollo动态修改)

3.url带特殊字符处理:

某些情况下,参数带特殊字符,如下,Gateway也会响应400

http://localhost:8280/api/xxx/xxx/smsCode?phone=|135****6862

http://localhost:8280/api/xxx/xxx/smsCode?phone=?135****6862

解决方案是增加UrlParamHandler,获取url对其参数做urlencode

注意:hutool工具的URLUtil.encodeQuery会对一些RSA加密的+转换为空格,需要用URLUtil.encodeAll或者java原生java.net.URLEncoder,这2个又会把所有的路径参数、=、?之类的也转换,所以下面写了个复杂的逻辑去获取参数值,仅参数值做urlencode

 

怎么样?如果你觉得有用的话,还不快快收藏起来!!!

附:涉及的代码目录

github: GitHub - 897665787/springcloud-template: 一个基于springcloud netflix微服务框架,记录了关于微服务开发的一些最佳应用,欢迎大家学习指导。

gitee:springcloud-template: 一个基于springcloud netflix开发的脚手架,记录了关于微服务开发中一些基础功能、通用功能的最佳设计,欢迎大家学习、指导。

springcloud-template
└── template-gateway└── netty -- 日志配置└── CustomHttpObjectDecoder -- 复制于源码└── CustomHttpRequestDecoder -- 复制于源码└── CustomHttpServerCodec -- 复制于源码└── NettyWebServerCustomizer -- 配置初始化└── UrlParamHandler -- 使用urlencode替换特殊字符

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/746079.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT使用dumpcpp为COM生成h及cpp的方式,COM是C#的dll注册的

目录 1.C#的dll注册为COM,采用bat的方式 2.通过qt的dumpcpp来生成h及cpp文件 3.h文件和cpp文件处理。 台达数控系统的C#的dll dumpcpp用的tlb文件 dumpcpp生成的原生h文件 dumpcpp生成的原生cpp dump生成后的的原生cpp文件修改后的cpp文资源 dump生成后的的…

AI短视频矩阵系统介绍|罐头鱼AI视频批量生成

智能化管理,轻松批量剪辑短视频! 近年来,随着短视频营销行业的发展,我们推出了一款AI短视频矩阵系统,旨在帮助用户管理、剪辑和发布短视频内容,从而提升品牌影响力。让我们来看看这款系统都提供了哪些功能&…

C:数据结构王道

初始化顺序表(顺序表中元素为整型),里边的元素是1,2,3,然后通过scanf读取一个元素(假如插入的是6),插入到第2个位置,打印输出顺序表,每个元素占3个空格,格式为…

在哪些领域中最需要使用 OCR 识别技术?

光学字符识别(OCR)技术能够将不同格式的印刷或手写文本转换为机器编码的文本,这一技术在许多领域都发挥着重要作用,尤其是在需要大量处理文档和图像数据的场景中。以下是一些最需要使用OCR识别技术的领域: 1. 办公自动…

Windows Server 各版本搭建终端服务器实现远程访问(03~19)

一、Windows Server 2003 左下角开始➡管理工具➡管理您的服务器,点击添加或删除角色 点击下一步 勾选自定义,点击下一步 点击终端服务器,点击下一步 点击确定 重新登录后点击确定 点击开始➡管理工具➡计算机管理,展开本地用户…

openssl3.2 - 官方demo学习 - encode - ec_encode.c

文章目录 openssl3.2 - 官方demo学习 - encode - ec_encode.c概述笔记产生ecc私钥产生ecc公钥测试工程备注备注END openssl3.2 - 官方demo学习 - encode - ec_encode.c 概述 官方demos/encode 目录中给了2个例子工程 功能是载入(RSA/ECC)公钥, 然后自己就可以拿内存中的公钥对…

mupdf渲染过程(一):颜色

mupdf除了解析PDF功能之外,还有一个强大的功能就是渲染文字和图像,本文介绍mupdf渲染过程中涉及到的颜色问题:包括颜色空间,颜色转换,lcms的使用。 1.初始化 mupdf初始化第一步是实例化fz_context *ctx,fz…

利用适配器模式使用第三方库

文章目录 一、为什么要使用适配器模式二、适配器模式使用第三方库示例 一、为什么要使用适配器模式 适配器模式是一种设计模式,用于将一个类的接口转换成客户端所期望的另一个接口。适配器模式的主要目的是使不兼容的接口能够一起工作。以下是一些使用适配器的原因&…

OpenCV开发笔记(七十七):相机标定(二):通过棋盘标定计算相机内参矩阵矫正畸变摄像头图像

若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/136616551 各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究 红胖子(红模仿)的博…

TypeScript的基础类型和高级类型梳理总结

一、基础类型 1、boolean 布尔类型 表示逻辑值,可以是 true 或 false let isBoolean:boolean false 2、number 数字类型 表示整数和浮点数(例如 42,3.14159),不论是十进制、二进制、八进制还是十六进制&#xff…

Rust镜像配置

cargo镜像配置 找到.cargo目录并创建config文件,输入以下内容即可,windows一般在C:\Users\用户目录\.cargo,linux执行vim ~/.cargo/config即可。然后将下面内容赋值粘贴进去 [source.crates-io] registry = "https://github.com/rust-lang/crates.io-index" rep…

Visual Studio 2022 配置“Debug|x64”的 Designtime 生成失败。IntelliSense 可能不可用。

今天写代码,无缘无故就给我整个这个错误出来,我一头雾水。 经过我几个小时的奋战,终于解决问题 原因就是这个Q_INTERFACES()宏,我本想使用Q_DECLARE_INTERFACE Q_INTERFACES这两个Qt宏实现不继承QObject也能使用qobjec…

C语言自学笔记17----结构体struct与位域与关键字typedef

C 语言结构体(struct) 为什么在C中使用结构? 假设您要存储有关一个人的信息:他/她的姓名,身份证号和薪水。您可以创建不同的变量name,citNo和salary存储此信息。 如果您需要存储多个人的信息怎么办?现在,你…

VSCode提交代码

VSCode提交代码方式: 先在电脑本地文件夹中打开git的bash窗口使用git clone https://github.com/xxxx/克隆仓库地址到本地,并生成一个项目的文件夹打开VSCode,点击文件按钮,打开加载项目的文件夹对于VSCode设置Git路径&#xff…

Three 材质纹理 (总结三)

THREE.MeshLambertMaterial(网格 Lambert 材质) 该材质使用基于非物理的Lambertian模型来计算反射率。可以用来创建暗淡的并不光亮的表面,该材质非常易用,而且会与场景中的光源产生反应。 MeshLambertMaterial属性 # .color : …

蓝桥杯刷题|02入门真题

[蓝桥杯 2022 省 B] 刷题统计 题目描述 小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 a 道题目,周六和周日每天做 b 道题目。请你帮小明计算,按照计划他将在第几天实现做题数大于等于 n 题? 输入格式 输入一行包含三个整数…

Linux之线程互斥

目录 一、问题引入 二、线程互斥 1、相关概念 2、加锁保护 1、静态分配 2、动态分配 3、锁的原理 4、死锁 三、可重入与线程安全 1、概念 2、常见的线程不安全的情况 3、常见的线程安全的情况 4、常见不可重入的情况 5、常见可重入的情况 6、可重入与线程安全联系…

google scholar谷歌学术搜索技巧合集【补充ing】

今天发现和百度学术更新速度差太多,引用数量也不对,故搜集谷歌学术搜索技巧,以尽快查找所需。 筛选合集: 谷歌学术高级搜索技巧大放送 - 知乎 Google Scholar 谷歌学术文献检索技巧总结 - 知乎 Google Scholar谷歌学术文献检索技…

Linux 部署 Samba 服务

一、Ubuntu 部署 Samba 1、安装 Samba # 更新本地软件包列表 sudo apt update# 安装Samba sudo apt install samba# 查看版本 smbd --version2、创建共享文件夹,并配置 Samba 创建需要共享的文件夹,并赋予权限: sudo mkdir /home/test sud…

vue3 依赖注入provide/inject

建议在非父子(或不相关)组件传值时进行使用 场景:App.vue 引用了A组件,A组件中有引用了B组件,甚至B有引用了C组件等时,这些组件共同使用了一个值,建议使用provide/inject的方式进行传值。 注意…