会,cjson.decode将json大整数静默转为lua number导致精度丢失,因lua number基于ieee 754双精度浮点数,无法精确表示超2⁵³−1的整数,且该损失不可逆。

Redis Lua 脚本里 cjson.decode 会把大整数转成 number 吗?
会,而且是静默丢失精度——cjson.decode 在 OpenResty 或 Redis 内置 Lua 环境中,把 JSON 中的数字一律解析为 Lua number 类型(IEEE 754 双精度浮点数),不区分整数/浮点、大小或是否超限。一旦原始 JSON 里有超过 2⁵³ − 1 的整数(比如 13579246810111213),decode 后就变成 13579246810111212,没有警告,也无法恢复。
为什么不能靠 cjson.encode 回写来“修复”?
因为精度在 decode 阶段就已经丢了,encode 只是对一个错误的 number 值做字符串化,结果仍是错的。例如:
local json_str = '{"id":13579246810111213}'
local data = cjson.decode(json_str) -- data.id 已是 13579246810111212
return cjson.encode(data) -- 输出 {"id":13579246810111212},不是原值
-
cjson不支持 BigInt 或任意精度整数,Lua 本身也没有原生 64 位整型 - OpenResty 的
cjson是 C 实现,底层用 double 存储所有数字 - 即使你用
tostring(data.id),得到的仍是四舍五入后的字符串
真正能落地的绕过方案有哪些?
核心思路:不让大数经过 cjson.decode 的 number 转换路径。以下三种方式按优先级排列:
- 前端/后端约定:所有可能超限的字段(如
id、user_id、timestamp)统一以字符串形式传入 JSON,比如{"id":"13579246810111213"};Lua 脚本里直接用data.id当字符串处理,全程不转 number - 预处理 JSON 字符串:在调用
cjson.decode前,用string.gsub把目标字段的数字字面量加引号,例如:json_str = string.gsub(json_str, '"(id)":(%d+)', '"%1":"%2"');注意正则要匹配具体字段名,避免误改"count":123这类小整数 - 放弃 cjson,改用纯 Lua 实现的 JSON 解析器(如
dkjson)并自行 hook 数字解析逻辑——但 Redis 不内置dkjson,需手动注入,运维成本高,不推荐
最容易被忽略的一点:Redis Lua 脚本返回值最终仍要经由 Redis 协议序列化,而协议只支持 integer / bulk string / multi-bulk 等有限类型;如果你真需要把大整数当数值参与计算(比如自增),只能靠字符串拼接 + 客户端侧解析,Lua 层无法安全完成算术运算。











