平时对接接口,我们都默认前端传过来的字段是唯一的、干净的。解析参数、绑定实体、执行业务逻辑,整个过程不会做任何重复字段校验。
绝大多数开发压根不会考虑,同一个请求里,会出现两次一模一样的参数字段。这属于认知盲区,框架默认帮我们处理了,久而久之没人在意这种边界情况。但线上真实场景里,这种异常请求确实存在,而且会引发非常诡异的数据错乱。
之前线上遇到过几次无厘头的参数赋值错误,前端说只传了一个值,后端接收出来的数据完全不对,两边核对日志耗时很久,最后才查到根源是参数重复传入导致的解析异常。
不同请求格式,重复参数的处理逻辑完全不一样。
最坑的是JSON请求体。很多人以为JSON天然不允许重复key,实际线上通过篡改请求报文、特殊工具发包,完全可以构造出重复字段的JSON结构体。
主流解析框架在遇到重复key时,不会抛错、不会告警,默认直接覆盖原值。大部分情况下是后传的值覆盖前面,极少数版本会反向覆盖,完全没有统一标准。
这就导致一种随机Bug:同样的接口、同样的参数,偶尔赋值正确、偶尔数据被篡改,没有任何规律可言。
这种问题本地极难复现。正常前端打包、接口调试工具,都会自动过滤重复字段,不会生成非法请求报文。只有线上恶意请求、老旧客户端、第三方异常回调,才会触发这类问题。
很多项目因此出现过少量用户数据异常、状态莫名变更、表单提交内容错乱的问题,最后都不了了之,没人定位到是参数重复解析导致。
还有一个很隐蔽的场景,参数大小写混写叠加重复字段。
部分客户端传参不规范,同一字段大小写交替出现,同时存在多个相似key。框架解析时区分大小写,会同时读取多个字段,赋值错乱,导致最终参数拼接完全偏离预期。
业务代码本身没有任何问题,所有逻辑都是按正常参数执行,输入数据本身被污染,最终输出结果自然出错。
更麻烦的是日志记录的盲区。
很多项目的请求日志,是解析完成后打印的参数,并不是原始报文。即便原始请求存在大量重复字段,日志里也只会展示最终解析完毕的有效值。
这就导致排查问题时,日志参数完全正常,根本看不出原始请求存在异常,彻底断掉排查线索,只能盲猜问题。
经历过这类问题之后才发现,我们平时依赖的框架自动解析,本身存在很多隐性容错逻辑。
框架为了保证请求不报错,默默兼容了各种非法参数、重复字段、异常格式,表面上服务平稳运行,实则悄悄篡改了输入数据。
很多看似无解的线上偶现Bug,不是代码逻辑漏洞,而是过度兼容带来的副作用。
现在做接口校验,除了常规的非空、长度、格式校验,我会针对性做参数唯一性校验。对核心业务接口直接拦截非法重复参数,宁可拒绝请求,也不接受框架自动兼容的脏数据。
接口稳定性,很多时候就是靠这些没人关注的微小边界细节堆出来的。
技术复盘:被多数人忽略的请求重复参数问题