如何在Redis Lua脚本中安全地解析和操作JSON数据?

P粉602998670

P粉602998670

2026-07-27

502人浏览

原创

redis lua脚本中只能用内置cjson库解析json,因其无需额外模块且兼容性好;而json.set/get需redis.json模块支持,未加载时会报错。

如何在redis lua脚本中安全地解析和操作json数据?

Redis Lua脚本里能解析 JSON,但必须用 cjson 库,且不能直接操作嵌套字段——它只提供 cjson.decode()cjson.encode() 两个基础能力,所有字段访问、修改、合并都得靠 Lua 表操作手动完成。

为什么不能直接用 JSON.SET/JSON.GET?

因为 JSON.SETJSON.GETredis.json 模块的命令,不是原生 Redis 的一部分。如果你的 Redis 实例没加载该模块(比如标准社区版或旧版本),执行这些命令会报错:(error) ERR unknown command。而 cjson 是 Redis 内置的 Lua 库,只要 Redis ≥ 2.6 就可用,无需额外安装。

  • 检查是否支持:redis-cli EVAL "return cjson.decode('{}')" 0 —— 成功返回空表说明可用
  • 模块命令(如 JSON.GET user:1001 $.name)和 cjson 是两套体系,不能混用
  • 模块命令原子性强、语法简洁;cjson 灵活但易出错,尤其在处理 null、数字精度、转义字符时

cjson.decode() 常见崩溃点

传入非法 JSON 字符串会导致 Lua 脚本直接中断,并返回 (error) ERR Error running script,而不是返回 nil 或错误信息。这不是 Redis 的 bug,是 cjson 的设计:它不捕获解析异常。

php版微信js-sdk支付接口类
php版微信js-sdk支付接口类

php版微信js-sdk支付接口类

下载
  • 必须用 pcall 包裹:local ok, res = pcall(cjson.decode, ARGV[1]),否则脚本一遇到 "{name:"Alice" 这种少引号的字符串就挂
  • cjson.decode()null 返回 Lua 的 nil,但 Lua 表中 nil 无法被序列化回 JSON —— 后续 cjson.encode() 会丢掉该字段
  • 浮点数可能丢失精度:cjson.decode('{"x":1.0000000000000001}')['x'] 在 Lua 中变成 1,再 encode 回去就是 {"x":1}

安全更新嵌套字段的最小可行写法

想把 {"user":{"profile":{"age":25}}} 中的 age 改成 26,不能硬拼字符串,也不能忽略缺失路径。正确做法是分三步:解码 → 深层赋值(带路径检查)→ 编码回写。

local cjson = require("cjson")
local json_str = redis.call("GET", KEYS[1])
if not json_str then return nil end
<p>local ok, data = pcall(cjson.decode, json_str)
if not ok then return "invalid json" end</p><p>-- 手动走路径:user.profile.age
if data.user and data.user.profile then
data.user.profile.age = tonumber(ARGV[1]) or 0
else
return "missing path"
end</p><p>redis.call("SET", KEYS[1], cjson.encode(data))
return "ok"</p>
  • 别用 string.gsub 替换字段值——JSON 字符串里字段名可能出现在值中(如 {"desc":"age=25"}),导致误改
  • 路径访问必须逐层判空,Lua 中 data.user.profile.age = 26profile 为 nil 时静默失败,不会报错也不会生效
  • 写回前务必 cjson.encode(),不要直接 .. 拼接,否则中文、引号、反斜杠全乱

什么时候该放弃 Lua + cjson?

当你需要频繁做“读-改-写”且涉及条件判断(比如 if age > 18 then set status="adult")、数组追加、字段存在性校验,或结构深度超过 2 层时,cjson 就开始吃力了。这时真正该做的不是写更长的 Lua,而是换方案:

  • 升级到 Redis Stack 或启用 redis.json 模块,用 JSON.SET key $.user.profile.age 26 一行搞定
  • 拆 key:把 user:1001 的 profile 单独存为 user:1001:profile,用 Hash 或 String 存,避免 JSON 解析开销
  • 客户端解析:如果并发不高、延迟不敏感,GET + 客户端解析 + SET 更清晰,也更容易 debug

最常被忽略的一点:Lua 脚本里没有日志,出错了只能靠返回值猜——所以 pcall 不是可选项,是必选项;而任何对 cjson.encode() 的调用,都要假设它可能因循环引用或 unsupported type(如 function)而崩溃。

相关专题

更多
js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

2023.06.20

1859

8

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.07.28

911

5

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.03

1154

5

js是什么意思
js是什么意思

JS是JavaScript的缩写,它是一种广泛应用于网页开发的脚本语言。JavaScript是一种解释性的、基于对象和事件驱动的编程语言,通常用于为网页增加交互性和动态性。它可以在网页上实现复杂的功能和效果,如表单验证、页面元素操作、动画效果、数据交互等。

2023.08.17

7910

11

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

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

2023.09.01

638

4

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

1234

5

Js中concat和push的区别
Js中concat和push的区别

Js中concat和push的区别:1、concat用于将两个或多个数组合并成一个新数组,并返回这个新数组,而push用于向数组的末尾添加一个或多个元素,并返回修改后的数组的新长度;2、concat不会修改原始数组,是创建新的数组,而push会修改原数组,将新元素添加到原数组的末尾等等。本专题为大家提供concat和push相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.14

1058

5

js截取字符串的方法介绍
js截取字符串的方法介绍

JavaScript字符串截取方法,包括substring、slice、substr、charAt和split方法。这些方法可以根据具体需求,灵活地截取字符串的不同部分。在实际开发中,根据具体情况选择合适的方法进行字符串截取,能够提高代码的效率和可读性 。

2023.09.21

1977

3

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

JavaScript生成随机数的方法,包括使用Math.random()方法生成指定范围内的随机整数、生成随机字符串和生成随机颜色。根据具体需求,可以选择适合的方法来生成随机数,以实现各种功能 。

2023.09.25

984

5

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
phpEnv手册
phpEnv手册

共0课时 | 0人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.5万人学习

Redis+MySQL数据库面试教程
Redis+MySQL数据库面试教程

共72课时 | 9万人学习