Lua - 变量(对)连接转义特殊字符 - Openresty Nginx

我不使用Lua,但需要在Openresty(nginx)中使用它,如链接所提供的那样。

Openresty有一个Lua模块 _我成功安装并正确运行了Openresty nginx版本,网站工作正常_。

这个 答案 显示如何将头部连接为字符串 $request_headers:

set_by_lua $request_headers '
  local h = ngx.req.get_headers()
  local request_headers_all = ""
  for k, v in pairs(h) do
    request_headers_all = request_headers_all .. "["..k..": "..v..\n"]"
  end
  return request_headers_all
';

我将上面Lua函数中的格式从 ""..k..": "..v..";" 改为了 "["..k..": "..v.."]"

日志格式:

log_format log_realip 'Host: "$host", Via : "$http_via", RemoteAddr: "$remote_addr", XForwardedFor: "$h
ttp_x_forwarded_for", 'RealIPRemoteAddr: "$realip_remote_addr" - $status - "$request_uri" - **"[HEADERS]" - $request_headers';**

Host: "192.168.1.4", Via : "-",
//仅显示[HEADERS]
....
"[HEADERS]" - [sec-ch-ua: \x22Chromium\x22;v=\x2288\x22, \x22Google Chrome\x22;v=\x228
8\x22, \x22;Not A Brand\x22;v=\x2299\x22][sec-ch-ua-mobile: ?0][cookie: __utmz=abcdef; frontend=abcdef; adminhtml=abcdef
08; TestName=Some Value][upgrade-insecure-requests: 1][accept-language: en-US,en;q=0.9][user-agent: Mozilla/5.0
 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36][accept
-encoding: gzip, deflate, br][accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/we
bp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9][sec-fetch-dest: document][host: 192.168.1.4][se
c-fetch-user: ?1][connection: keep-alive][sec-fetch-mode: navigate][cache-control: max-age=0][sec-fetch-site: n
one

当使用 $request_headers 字符串的 log_format 时,我得到了所有头部的字符串。但我试图创建一个 newline \n 将字符串分成几行。上面的例子是我添加了 \n,但看起来并未输出换行符到日志文件中。

我理解 request_headers_all .. 将字符串连接起来,但是这里的 key kvalue v : ""..k..": "..v..\n"" 是什么意思?

"..variablename.." 是什么意思,这是变量始终在Lua字符串内使用的方法吗?

我该如何在该字符串中创建换行符?或者nginx(openresty)无法输出换行符?

点赞
用户2858170
用户2858170

request_headers_all = request_headers_all .. "["..k..": "..v.."]\n"

这里包含语法错误。将 "["..k..": "..v..\n"]" 替换为 "["..k..": "..v.."]\n"

换行需要处于引号内,因为它是字符串的一部分,很可能在括号后添加换行符才有意义。

"..variablename.." 是什么意思?这是 Lua 字符串中变量的通用用法吗?

在变量上使用连接运算符会连接字符串值,如果是数字则连接其字符串表示形式,如果两者都不是,则调用 __concat 或者引发错误。

请参阅 https://www.lua.org/manual/5.4/manual.html#3.4.6

2021-02-02 11:18:36
用户8294610
用户8294610

如果你将 \n 添加到错误的位置,你可以改为 request_headers_all = request_headers_all .. "["..k..": "..v.."]\n" 添加一个换行记录。

在 Lua 中,.. 是一个连接符,用于连接两个字符串,例如:

print("hello" .. "world")

结果为 helloworld

你的代码 \n"]" 存在语法错误,因为 \n 不在字符串中。

Lua 字符串不能直接使用变量,通常使用 string.format 处理复杂的字符串。例如:

local test = "hello"
string.format("%s world",test) -- hello world

你可以使用 string.format 进行字符串连接。此外,你还可以使用 table.concat 来连接字符串。例如:

local test = {}
table.insert(test, "hello")
table.insert(test, "world")
local concated_string = table.concat(test, ' ')
print(concated_string) -- hello world
2021-02-02 11:22:18
用户13632900
用户13632900

上面的回答给了我一些指导,但是建议的格式仍然无法正常工作。在尝试使用string.format("%s %s\n",k,v)string.format("%s %s\\n",k,v)后,我仍然遇到了unfinished string错误或没有输出换行符(在第二个示例中尝试了转义字符串)。

基于给出的答案,我认为答案给出了正确的lua信息,所以决定最有可能的情况是lua + openresty做了不同的事情。

我将尝试更新标题以反映更具体的要求

TLDR

  1. 特殊字符的Openresty + lua字符串操作可能无法按预期工作,即使使用string.format()
  2. 从返回字符串的set_by_lua更改为允许更好的string.format()或字符串连接的set_by_lua_block
  3. 根据您的自定义/现有log_format更新nginx配置,并添加开关escape = none

全面解释

调查提供的链接答案set_by_lua函数文档:

注意自v0.9.17发布以来,不建议使用此指令。使用set_by_lua_block指令。

因此从原始的链接中的set_by_lua更改为:

set_by_lua $request_headers '
  return 'stringvalue'
';

我改为set_by_lua_block函数:

这个指令将Lua源直接内联在一对大括号({})中,而不是在一个Nginx字符串文字中(需要特殊字符转义)

set_by_lua_block $request_headers{
  local h = ngx.req.get_headers()
  local request_headers_all = ""
  for k, v in pairs(h) do
    local rowtext = ""
    rowtext = string.format("[%s %s]\n", k, v)
    request_headers_all = request_headers_all .. rowtext

  end
  return request_headers_all
}

重要的部分是这个_block {}函数正确地转义特殊字符。

然后我在日志文件中收到的输出为:x0A(换行字符文字)。

最后一步是更新nginx.conf文件与自定义log_format并添加escape=none

log_format log_realip escape=none "$nginx_variables"
2021-02-02 13:34:10
用户11251604
用户11251604

主要问题/难点在于包装软件如何处理换行符/转义字符,它是期望 "\n" 还是期望 "\r\n"

最终换行符只有在解释和打印后才实际存在,并且您正在创建一个从 Lua 引擎返回给包装器的大字符串,因此如何解释换行符取决于包装软件。

编辑:我错过了使用其他解析函数已经回答了这个问题。

此外,文档中指出,要使用原始解析函数,需要对转义字符进行双重转义。

在这里,\\\\d+ 通过 Nginx 配置文件解析器被简化为 \\d+,在运行之前被 Lua 语言解析器进一步简化为 \d+。

2021-02-04 14:36:02