Lua中使用gsub替换整个响应体出现重复结果的问题排查
问题成因
Lua原生模式匹配规则下,.* 会触发两次替换:
- 第一次为贪婪匹配,命中完整字符串的全部有效内容,触发第一次替换
- 匹配完成后光标移动到字符串末尾位置,由于
.*支持匹配0长度空串,会命中末尾的空位置触发第二次替换
该特性是Lua模式匹配的固有行为,与OpenResty body过滤阶段的逻辑无关,可通过原生Lua代码直接复现:
-- 执行输出:TESTINGTESTING 2 print(string.gsub("test content", ".*", "TESTING"))
这就是最终返回结果为TESTINGTESTING而非单个TESTING的根本原因。
修复方案
三种可落地的实现方式,按需选择即可:
- 直接赋值(性能最优,适配全量替换固定内容的场景):无需调用gsub做模式匹配,在响应体传输完成的节点直接给输出变量赋值目标内容即可
ngx.ctx.buffered = (ngx.ctx.buffered or "") .. ngx.arg[1] if ngx.arg[2] then ngx.arg[1] = "TESTING" else ngx.arg[1] = '' end - 锚定匹配起始位置:在匹配规则前增加
^锚点,强制从字符串起始位置做全量匹配,不会匹配末尾空串ngx.ctx.buffered = (ngx.ctx.buffered or "") .. ngx.arg[1] if ngx.arg[2] then ngx.arg[1] = ngx.ctx.buffered:gsub("^.*", "TESTING") else ngx.arg[1] = '' end - 限制替换次数:给gsub传入最大替换次数参数1,匹配到第一次完整内容后即终止替换流程,不会处理末尾空串
ngx.ctx.buffered = (ngx.ctx.buffered or "") .. ngx.arg[1] if ngx.arg[2] then ngx.arg[1] = ngx.ctx.buffered:gsub(".*", "TESTING", 1) else ngx.arg[1] = '' end
内容的提问来源于stack exchange,提问作者ant
相关产品推荐
相关产品推荐

