理解 Nginx+OpenResty 中行内 Lua 代码中字符串的引用

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

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

在 Ruby 中,实现可能类似于这样:

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

我是 Lua 的初学者,在 OpenResty 环境中我苦苦挣扎,直到终于让它工作为止。这是最终的工作方式:

   content_by_lua '
        -- ... 一些代码 ...
        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\\"")则这个错误会消失。虽然在相同的代码被拒绝在 Lua REPL 中时,但它在 OpenResty 中可行。

$ 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 中更优雅地表达。)

点赞
用户5287638
用户5287638

正如Egor所说的那样,这是因为nginx配置文件解析器在被Lua解析之前会剥离反斜杠字符\。在你的情况下,"\\"1.2.3.4\\""是正确的,因为它被nginx配置解析器解析为"\"1.2.3.4\"",然后被Lua解析为字符串"1.2.3.4"

如果你不想担心使用多少反斜杠,有几种可行的替代方案。最简单的方法是使用从OpenResty v0.9.17开始提供的content_by_lua_block

content_by_lua_block {
    -- ...一些代码...
    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的多行字符串语法

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

更多细节,请参见OpenResty文档

另外,如果你想完全避免使用表格,你可以使用string.rep制作相同的测试数据。

content_by_lua '
    -- ...一些代码...
    local ip = [["1.2.3.4"]]
    local fakeResponse = "[" .. string.rep(ip .. ", ", 4095) .. ip .. "]"
    --- ...
'
2017-05-23 02:52:37