JavaScript 中 JSON 怎么在前后端分离接口签名验签中保持对象键值顺序一致

阿枫君_9503

阿枫君_9503

2026-08-25

165人浏览

原创

json签名需按utf-8字典序统一键序以确保跨语言一致性,前端排序顶层键并递归处理嵌套对象或扁平化params,后端须同步实现相同排序规则及编码标准。

javascript 中 json 怎么在前后端分离接口签名验签中保持对象键值顺序一致

JSON 本身不保证对象键的顺序,ECMAScript 规范明确指出:对象属性遍历顺序(如 for...in、Object.keys()、JSON.stringify())在 ES2015+ 中**对字符串键按插入顺序保持一致**,但前提是键名符合“普通标识符”规则且未被重排(如数字字符串键会按数值大小排序)。然而,在接口签名验签场景中,仅依赖语言默认行为仍不可靠——尤其涉及不同语言后端(如 Java、Go)、不同 JSON 库或历史兼容性时,键序极易错乱,导致签名不一致、验签失败。

签名前强制统一键序:按字典序序列化

最稳妥的做法是:签名计算前,将待签名对象的所有键按 UTF-8 字典序(而非插入序)排序,再序列化。这能确保前后端无论使用何种 JSON 库,只要遵循同一排序规则,结果就完全一致。

  • 前端 JavaScript 示例(使用 JSON.stringify 配合排序后的 key 数组):


const payload = {
  timestamp: 1717023456,
  nonce: "abc123",
  method: "user.get",
  params: { id: 1001, status: "active" }
};


const sortedKeys = Object.keys(payload).sort();


const orderedPayload = {};
for (const key of sortedKeys) {
  orderedPayload[key] = payload[key];
}


const signString = JSON.stringify(orderedPayload);
// → {"method":"user.get","nonce":"abc123","params":{"id":1001,"status":"active"},"timestamp":1717023456}
// ✅ 所有键严格字典序

避免嵌套对象干扰:签名字段扁平化或约定结构

深层嵌套对象的键序难以统一控制(如 params.id 和 params.status 的顺序依赖 params 自身序列化逻辑)。推荐两种实践:

Feishu calendar sync, local ics to json data for AI agent
Feishu calendar sync, local ics to json data for AI agent

将ICS日历文件转为JSON格式,用于飞书日历导入导出及数据集成。

下载
  • 方案一(推荐):签名只包含顶层字段,且 params 作为 JSON 字符串参与签名(即先序列化 params,再拼入签名原文)。这样 params 内部顺序由前端单方决定,后端解析后直接比对字符串,无需重复排序。
  • 方案二:约定 params 必须为字典序排序后的 JSON 字符串,由前端生成并透传。后端收到后原样用于签名计算,不重新解析再序列化。

后端必须同步实现相同排序逻辑

前端按字典序排序,后端也必须用完全相同的规则处理:

  • Java(Jackson):禁用默认的“按声明顺序”,改用 @JsonPropertyOrder(alphabetic = true) 或手动构建 TreeMap;
  • Go(encoding/json):标准库默认无序,需用 map[string]interface{} 配合 sort.Strings + 自定义序列化;
  • Python(json.dumps):传入 sort_keys=True 即可。

关键点:前后端使用的“字典序”必须基于相同编码(通常是 UTF-8 字节序),避免 Unicode 归一化差异。

额外建议:签名原文排除无关字段,加盐防篡改

签名计算前应明确字段白名单(如只含 method、timestamp、nonce、params),过滤掉 sign、signature 等签名自身字段,防止循环依赖。同时可加入固定 salt(如 API 密钥)参与哈希,提升安全性:

const signContent = JSON.stringify(orderedPayload) + "&salt=your_api_secret";
const signature = CryptoJS.HmacSHA256(signContent, apiKey).toString();

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

相关专题

更多
python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2243

5

前端和后端的区别
前端和后端的区别

前端关注的是用户界面的设计和交互,而后端则注重数据处理和逻辑控制。想了解更多前端后端的相关内容,可以阅读本专题下面的文章。

2024.03.19

5950

13

后端的主要工作内容介绍
后端的主要工作内容介绍

后端是应用程序的服务端部分,负责核心任务,如数据库交互、业务逻辑处理和响应客户端请求。想了解更多后端的相关内容,可以阅读本专题下面的文章。

2024.03.19

5266

10

js获取数组长度的方法
js获取数组长度的方法

在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

4466

5

js刷新当前页面
js刷新当前页面

js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

2023.07.04

1109

3

js四舍五入
js四舍五入

js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

2023.07.04

4384

6

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

2023.09.01

880

4

JavaScript转义字符
JavaScript转义字符

JavaScript中的转义字符是反斜杠和引号,可以在字符串中表示特殊字符或改变字符的含义。本专题为大家提供转义字符相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

1776

5

js生成随机数的方法
js生成随机数的方法

js生成随机数的方法有:1、使用random函数生成0-1之间的随机数;2、使用random函数和特定范围来生成随机整数;3、使用random函数和round函数生成0-99之间的随机整数;4、使用random函数和其他函数生成更复杂的随机数;5、使用random函数和其他函数生成范围内的随机小数;6、使用random函数和其他函数生成范围内的随机整数或小数。

2023.09.04

3225

4

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WebStorm 官方调试文档
WebStorm 官方调试文档

共0课时 | 0人学习

React 教程
React 教程

共58课时 | 12.1万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 6.6万人学习