使用Nginx Lua模块写入文件

我正在尝试使用 Nginx Lua 模块 进行实验。目前,我的目标只是将某些HTTP响应保存到本地磁盘文件中。

阅读了一些教程之后,我了解到可以使用 body_filter_by_lua 指令来实现这个目的。我的方法很简单,只是在 nginx.conf 文件中嵌入一些 Lua 代码,从 ngx.arg 中检索响应体,然后使用标准的 Lua io 设施将其写入磁盘。

我以前从没有用过 Lua 进行编程,但我曾经在其他脚本语言如 Python 中进行过大量编程,所以我发现学习 Lua 的基础知识相对容易。

尽管如此,我的方法并没有起作用,nginx的 error.log 表明问题在于我打开的 file 对象是 nil

以下是我在 nginx.conf 文件中放置的 Lua 代码(经过修改以提高可读性):

   location /foo {
        proxy_pass http://my_upstream_proxy;
        proxy_cache my_cache;
        proxy_redirect default;
        proxy_set_header Host      $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        body_filter_by_lua '
            local resp_body = ngx.arg[1]
            ngx.ctx.buffered = (ngx.ctx.buffered or "") .. resp_body
            if ngx.arg[2] then
                ngx.var.resp_body = ngx.ctx.buffered
            end

            local file = io.open("TEST.txt", "w+b")
            file:write(resp_body)
            file:close()
        ';
    }

这里的想法是,nginx只需将请求转发给代理,然后将响应体写入本地文件。

我使用以下命令进行测试:

curl http://www.google.com --proxy http://localhost:80

但是nginx返回了一个空回复。

我查看错误日志,并看到:

2016/12/15 11:51:00 [error] 10056#0: *1 failed to run body_filter_by_lua*: body_filter_by_lua:9: attempt to index local 'file' (a nil value)
stack traceback:
        body_filter_by_lua:9: in function <body_filter_by_lua:1> while sending to client, client: 127.0.0.1, server: test-server, request: "GET http://www.google.com/ HTTP/1.1", upstream: "http://69.187.22.138:82/", host: "www.google.com"

那么为什么我的本地 file 变量是 nil 呢?当我使用 bash 打开 Lua 控制台时,我能够轻易地打开/创建一个新的本地文件并写入文本,没有任何问题。

那么我做错了什么?起初,我认为可能是某些权限问题,nginx无法在当前工作目录中写入文件,但我理解 nginx 是以 root 身份运行的。我尝试了类似于 /home/myusername/NGINX.txt 的绝对路径,但仍然失败了,文件是 nil。我无法获得有关 file 为什么为 nil 的更具体错误。

那么我做错了什么?

点赞
用户891636
用户891636

在 Lua 上不是专家,但在我的尝试中,我学到了将 "io.open" 调用包装在 "assert" 函数中。请参阅 assert 的文档

local file = assert(io.open("TEST.txt", "w+b"), "Inaccessible file")

这可能只是证实了代码失败的位置。看着这一行,我不知道 "w+b" 中的 "b" 模式是什么。

你是指要覆盖就像在 io.open("TEST.txt", "w") 中,还是追加就像在 io.open("TEST.txt", "a") 中?

如果你用这些测试仍然出现错误,那么就意味着无法实际访问文件。

2016-12-16 08:12:11
用户2346535
用户2346535

我认为你应该将以下代码修改为:

local file = io.open("TEST.txt", "a")

而不是:

local file = io.open("TEST.txt", "w+b")
2019-08-21 07:34:59
用户15430342
用户15430342

Permission issue

无权在该位置创建/打开 "test.txt"。对于我来说,是在/usr/local/nginx-1.14.2/sbin/中。

解决方法: 授予权限。在我的测试环境中,/usr/local/nginx-1.14.2/ sudo chomd -r 777

为了找到真正的问题,可以尝试替换您的 "io.open" 部分,如下所示:

handle_name, err = io.open(file,"w")
print(err)

使用上面的lua语句,我得到了 "permission denied" 的错误信息。

2021-03-19 07:11:16
用户14022966
用户14022966

io.open 函数如果无法打开文件,则会返回 nil。你可以获取错误信息:

local file, err = io.open("TEST.txt", "w+b")
if file == nil then
    print("无法打开文件: " .. err)
else
    file:write(resp_body)
    file:close()
end
2021-03-19 14:09:45