了解 Nginx+OpenResty 中内联 Lua 代码中字符串的引用

Understanding quoting of strings in inline Lua code in Nginx+OpenResty

为了测试,我需要使用 OpenResty 在 Nginx 服务器中创建一些假数据。我需要创建一个复制一个 IP 地址的数组,例如:

 ["1.2.3.4", "1.2.3.4", ...]

在 Ruby 中,实现可能如下所示:

 "[" + (["\"1.2.3.4\""] * 4096).join(", ") + "]"

我是 Lua 的初学者,为了让它在 OpenResty 环境中工作,我付出了很多努力。这似乎终于奏效了:

   content_by_lua '
        -- ... some code ...
        local ips = {}
        for i=1,4096 do ips[i] = "\"1.2.3.4\"" end
        local fakeData = table.concat(ips, ", ")
        local fakeResponse = "[" .. fakeData .. "]"
        --- ...
   '

我在字符串引用方面遇到了一些问题。首先,我尝试了 '"1.2.3.4"',它在内联 Lua 部分不起作用。这是可以理解的,因为 ' 字符已经是 content_by_lua 部分的分隔符。

接下来,我尝试了 "\"1.2.3.4\"",我希望它能工作,但它导致了这个(令人困惑的)错误:

failed to load inlined Lua code:
content_by_lua(nginx.conf:235):17: malformed number near '1.2.3.4'

通过反复试验,我发现如果使用双引号 ("\"1.2.3.4\""),此错误就会消失。这在 OpenResty 中有效,尽管如果我在 Lua REPL:

中尝试相同的代码会被拒绝
$ rep.lua 
Lua REPL 0.8
> "\"1.2.3.4\""
[string "REPL"]:1: unexpected symbol near '"\"'

为了帮助我理解并成为更好的Lua/OpenResty程序员,我对引用有一些疑问:

  1. 为什么需要双引号(在 OpenResty 中)? (为什么 "\"1.2.3.4\"" 而不是 "\"1.2.3.4\""?)
  2. 为什么 OpenResty 的行为与 Lua REPL 不同?
  3. 是否可以在 content_by_lua 部分中使用单引号? (简化为'"1.2.3.4"'

(另外,一个无关的问题困扰着我。有没有更简单的代码表达方式?当我将它与我的 Ruby 片段进行比较时,我很确定它也可以表达在 Lua 中更优雅。)

正如 Egor 所说,这是因为反斜杠字符 \ 在被 Lua 解析之前被 nginx 配置文件解析器删除。在您的情况下,"\"1.2.3.4\"" 是正确的,因为它被 nginx 配置解析器解析为 "\"1.2.3.4\"",然后被 Lua.

解析为字符串 "1.2.3.4"

如果您不想担心要使用多少个反斜杠,有两种选择。最简单的是使用 content_by_lua_block,从 OpenResty v0.9.17 开始可用。

content_by_lua_block {
    -- ... some code ...
    local ips = {}
    for i=1,4096 do ips[i] = '"1.2.3.4"' end
    local fakeData = table.concat(ips, ", ")
    local fakeResponse = "[" .. fakeData .. "]"
    --- ...
}

如果您不能在您的 OpenResty 版本中使用 Lua 块,您可以使用 Lua 的 multiline string syntax.

content_by_lua '
    -- ... some code ...
    local ips = {}
    for i=1,4096 do ips[i] = [["1.2.3.4"]] end
    local fakeData = table.concat(ips, ", ")
    local fakeResponse = "[" .. fakeData .. "]"
    --- ...
'

有关详细信息,请参阅 OpenResty docs

此外,如果您想完全避免使用表格,您可以使用 string.rep.

制作相同的测试数据
content_by_lua '
    -- ... some code ...
    local ip = [["1.2.3.4"]]
    local fakeResponse = "[" .. string.rep(ip .. ", ", 4095) .. ip .. "]"
    --- ...
'