1. 指令
经过 Lua 编写 Nginx 脚本的基本构建块是指令。指令经常使用于指定 Lua 代码是几时执行的以及如何使用运行的结果。下图展现了指令执行的顺序。
html
lua_capture_error_log
语法:lua_capture_error_log size
默认:none
上下文:http
启用一个指定大小的缓冲区来捕获全部的 Nginx 错误日志,而不是保存到文件或磁盘中。nginx
以下,可使用 k 或 m 表示大小:git
lua_capture_error_log 100k;
一个经验:4KB 缓存能够容纳大约 20 个典型的错误日志消息。github
注意事项:json
- 这个缓存不会增加,若是满了,则新的错误日志消息将会覆盖缓存中旧的消息。
- 这个缓存的大小必定要比单个的错误日志消息的大小更大。
- 能够经过lua-resty-core 库的 ngx.errlog 模块的 get_logs 函数来读取 Lua land 缓冲区的消息。这个 Lua API 将返回捕获的错误日志消息,而且将读取到的消息从全局捕获缓存区中移除,为任何新的错误日志消息腾出空间。基于这个缘由,若是用户读取缓冲去中的错误日志消息足够快的话不宜将该缓冲区配置得太大。
- error_log 指令指定的日志级别将会影响该缓冲区的捕获,该缓冲区仅捕获级别不低于 error_log 指令指定的日志级别的消息。用户能够经过 Lua API 函数 errlog.set_filter_level 来动态设置更高的过滤日志级别,这比静态的 error_log 指令更灵活。
- 若是没有使用 ./configure 选项 --with-debug 来编译 OpenResty 或 Nginx,则没法捕获调试日志。因为高昂的开销,在生产版本中强烈建议禁用调试体质。
lua_code_cache
语法:lua_code_cache on | off
默认:lua_lua_cache on
上下文:http, server, location, location if
- 在 *_by_lua_file 指令(相似 set_by_lua_file 和 content_by_lua_file)或 lua 模块中使能或禁止 Lua 代码的 lua 代码缓存功能。
- 当关闭时,经过 ngx_lua 提供的每一个请求都将在一个单独的 Lua VM 实例中运行。所以,由 set_by_lua_file,content_by_lua_file,access_by_lua_file 等中引用的 lua 文件都将不会被缓存,全部的 lua 模块都将从头开始加载。经过该指令,开发人员能够采用编辑并刷新的模式。
- 注意,当在 nginx.conf 配置文件中编辑内联 Lua 代码时,因为仅有 Nginx 配置文件解析器,因此在 nginx.conf 中内联写入的 lua 代码(如由 set_by_lua,content_by_lua,access_by_lua 和 rewrite_by_lua 指定的 lua 代码)将不会被更新。仅有的方法是经过发送 HUP 信号来从新加载配置文件或重启 Nginx。
- 即便启用了代码缓存,也没法缓存由 *_by_lua_file 中的 dofile 或 loadfile 加载的 lua 文件(除非你本身缓存告终果)。一般可使用 init_by_lua 或 init_by_lua_file 指令来加载全部这些文件,或者经过使这些 Lua 文件成功真正的 lua 模块并经过 require 来加载它们。
- ngx_lua 模块不支持 Apache mod_lua 模块可用的 stat 模式。
- 强烈禁止在生产环境中禁用 Lua 代码缓存,仅能够在开发期间使用。由于它会对总体性能产生负面的影响。例如,在禁用 lua 代码缓存后,"hello world" Lua 示例的性能可能会降低一个数量级。
lua_package_path
语法:lua_package_path <lua-style-path-str>
默认:LUA_PATH 环境变量内容或者 lua 编译的默认值
上下文:http
- 设置由 set_by_lua,content_by_lua 等指定的脚本使用的 lua 模块搜索路径。这个路径字符串是标准的 lua 路径格式,";;" 经常使用于表示原始的搜索路径。
- 从发行版 v0.5.0rc29 开始,能够在搜索路径中使用特殊符号 $prefix 或 ${prefix}来指示服务器前缀的路径,一般在 Nginx 服务器启动时经过 -p PATH 命令行选项来指定 server prefix。
lua_package_cpath
语法:lua_apckage_cpath <lua-style-cpath-str>
默认:LUA_CPATH 环境变量的内容或 lua 的默认编译
上下文:http
- 设置经过由 set_by_lua,content_by_lua 等指定的脚本的 Lua C-module 的搜索路径。这个 cpath 字符串是标准的 lua cpath 格式,";;" 经常使用于表示原始的 cpath。
- 从 v0.5.0rc29 发行版开始,能够在搜索路径字符串中使用特殊字符 $prefix 或 ${prefix} 来指示 server prefix(该前缀一般在 Nginx 服务器启动时经过 -p PATH 命令行选项来指定)。
init_by_lua
语法:init_by_lua <lua-script-str>
上下文:http
阶段:加载配置
- 注意在 v0.9.17 发行版之后不鼓励使用该指令,应使用 init_by_lua_block 指令代替。
- 当 Nginx master 进程(若是有)在加载 Nginx 配置文件的时候,在全局 Lua VM 级别上运行由参数
<lua-script-str>
指定的 lua 代码。
- 当 Nginx 接收到 HUP 信号并开始从新加载配置文件时,Lua VM 将会被从新建立,且 init_by_lua 也将在新的 VM 上再次运行。若是 lua_code_cache 指令是关闭的(默认打开),init_by_lua 处理程序将在每一个请求上都运行一次,所以这这种特殊模式下,老是每一个请求建立一个独立的 Lua VM。
- 一般,你能够经过该挂钩在服务器启动时预加载 Lua 模块,并利用现代操做系统的写时复制(COW)优化。这里是一个预加载 Lua 模块的示例:
# this runs before forking out nginx worker processes:
init_by_lua_block { require "cjson" }
server {
location = /api {
content_by_lua_block {
-- the following requrei() will just return
-- the already loaded module from package.loaded:
ngx.say(require "cjson".encode{dog = 5, cat = 6} -- {"dog":5,"cat":6}
}
}
}
- 也能够在这个阶段初始化 lua_shared_dict shm 存储。以下示例:
lua_shared_dict dogs 1m;
init_by_lua_block {
local dogs = ngx.shared.dogs;
dogs:set("Tom", 56)
}
server {
location = /api {
content_by_lua_block {
local dogs = ngx.shared.dogs;
ngx.say(dogs:get("Tom"))
}
}
}
- 但注意,lua_shared_dict shm 共享内存将不会经过从新加载配置(例如经过 HUP 信号)清除。在这种状况下,若是你不想在 init_by_lua 代码中从新初始化 shm 内存,则须要在 shm 内存中设置一个自定义 flag,并在 init_by_lua 代码中老是检测该 flag。
- 由于该 Lua 代码在 Nginx fork 出 worker 子进程前运行,因此在这里加载的数据或代码将享受许多操做系统在全部 worker 进程中提供的写时复制功能,这将节省大量的内存。
- 不要在此上下文中初始化你本身的 Lua 全局变量,由于使用的 Lua 全局变量有性能损失,而且可能致使全局命名空间污染(更多细节参阅Lua Variable Scope)。建议的方法是使用正确的 Lua 模块文件(但不要使用标准 Lua 函数模块去定义 Lua 模块,由于它也会污染全局命名空间),同时在 init_by_lua 或其余上下文中调用 require 去加载你本身的模块文件(require() 会将加载的模块缓存在全局的 Lua 注册表 package.loaded 中,所以你的模块仅在整个 Lua VM 实例中加载一次)。
- 在该上下文中,仅支持一小部分 Lua 的 Nginx API:
- 日志 API:ngx.log 和 print
- 共享字典 API:ngx.shared.DICT
- 在将来用户请求中,该上下文将支持更多的 Lua 的 Nginx API。
- 基本上,你能够在此上下文中安全地使用阻塞 I/O 的 Lua 库,由于在服务器启动期间阻塞 master 进程彻底是能够的。甚至 Nginx 内核也会在配置加载阶段阻塞(至少在解析 upstream 域名时)。
- 应该很是当心在此上下文中注册的 Lua 代码中潜在的安全漏洞,由于 Nginx master 进程一般在 root 用户下运行。
init_by_lua_block
语法:Init_by_lua_block { lua-script }
上下文:http
阶段:加载配置
- 与 init_by_lua 指令相似,不一样之处在于此指令直接在一对花括号({})内部而不是在 Nginx 字符串(须要特殊字符串转义)中内联 lua 代码。如:
init_by_lua_block {
print("I need no extra escaping here, for example: \r\nblah")
}
init_by_lua_file
语法:init_by_lua_file <path-to-lua-script-file>
上下文:http
阶段:加载配置
init_worker_by_lua
语法:init_worker_by_lua <lua-script-str>
上下文:http
阶段:启动 worker 时
- 在 v0.9.17 版本后不鼓励使用此指令,改用 init_worker_by_lua_block 指令代替。
- 当 master 进程使能时,在每一个 Nginx worker 进程启动时运行指定的 Lua 代码。当 master 进程被禁用时,这个钩子将在 init_by_lua* 以后运行。
- 这个钩子经常使用于建立每一个 worker 重复发生的计时器(经过 ngx.timer.at ),用于后端运行情况检查或其余定时工做。以下示例:
init_worker_by_lua '
local delay = 3 -- in seconds
local new_timer = ngx.timer.at
local log = ngx.log
local ERR = ngx.ERR
local check
check = function(premature)
if not premature then
-- do the health check or other routine work
local ok, err = new_timer(delay, check)
if not ok then
log(ERR, "failed to create timer: ", err)
return
end
end
end
local hdl, err = new_timer(delay, check)
if not hdl then
log(ERR, "failed to create timer: ", err)
return
end
';
- 自 v0.10.12 版本以来,该钩子再也不在 cache manager 和 cache loader 进程中运行。
init_worker_by_lua_block
语法:init_worker_by_lua_block { lua-script }
上下文:http
阶段:启动 worker 时
- 与 init_worker_by_lua 指令相似,不一样之处在于此指令直接在一对花括号({})内部而不是在 NGINX 字符串文字(须要特殊字符转义)中内联 Lua 代码。以下:
init_worker_by_lua_block {
print("I need no extra escaping here, for example: \r\nblah")
}
- 自 v0.10.12 版本以来,该钩子再也不在 cache manager 和 cache loader 进程中运行。
init_worker_by_lua_file
语法:init_worker_by_lua_file <lua-file-path>
上下文:http
阶段:启动 worker 时
与 init_worker_by_lua 相似。c#
content_by_lua
语法:content_by_lua <lua-script-str>
上下文:location,location if
阶段:content
- 注意在 v0.9.17 发行版以后不鼓励使用此指令,改成使用 content_by_lua_block 指令代替。
- 做为一个 "content handler" 为每一个请求执行在
中指定的 lua 代码字符串。该 lua 代码可能会进行 API 调用,而且在独立的全局环境(例如 sandbox)中做为一个新派生的协程执行。
- 不要在同一个 location 中同时使用该指令和其余的 content handler 指令。如,该指令和 proxy_pass 指令不该该在经过一个 location 中出现。
content_by_lua_block
语法:content_by_lua_block { lua-script }
上下文:location,location if
阶段:content
- 与 content_by_lua 指令相似,不一样之处在于该指令直接在一对花括号({})内联 lua 源码,而不是在 Nginx 字符串文件中(它须要特殊字符转义)。
示例:后端
content_by_lua_block {
ngx.say("I need no extra escaping here, for example: \r\nblah")
}
该指令最初是在 v0.9.17 发行版中引入的。api
content_by_lua_file
语法:content_by_lua_file <path-to-lua-script-file>
上下文:location,location if
阶段:content
- 等同于 content_by_lua,不一样之处在于
指定的文件包含 lua 代码,从 v0.5.0rc32 发行版开始,将执行 Lua/LuaJIT 字节码。
- Nginx 变量能够用在
字符串中以提供灵活性,可是这会带来一些风险,所以一般不建议这么作。
- 当给定一个相似 foo/bar.lua 这样的相对路径时,会转变为相对于 server prefix 的绝对路径(server prefix 是在 Nginx 服务器启动时,经过 -p PATH 命令行选项执行的)。
- 当 lua 代码缓存打开时(默认打开),用户代码在第一个请求时被加载一次并缓存,而且每次修改 lua 源码文件时都必须从新加载 Nginx 配置。能够经过 在 nginx.conf 中使用 lua_code_cache off 在开发期间临时禁用 lua 代码缓存,来避免从新加载 Nginx。
- 在动态分派的文件路径中支持 Nginx 变量,以下:
# CAUTION: conntents in nginx var must be carefully filtered,
# otherwise there'll be great security risk!
location ~ ^/app/([-_a-zA-Z0-9/]+) {
set $path $1;
content_by_lua_file /path/to/lua/app/root/$path.lua;
}
ssl_certificate_by_lua_block
语法:ssl_certificate_by_lua_block { lua-script }
上下文:server
阶段:在 SSL 握手以前
- 当 Nginx 将要与下游 SSL(https)链接开始 SSL 握手时,运行该指令指定的用户 Lua 代码。
- 该指令对于基于每一个请求而设置的 SSL 证书链和相应的私钥特别有用。从远端(如 cosocket API)加载此类非阻塞的握手配置也颇有用。此外,还能够在纯 Lua 中按要求执行 OCSP stapling handling。
- 另外一个典型的使用状况是在 lua-resty-limit-traffic#readme 库的帮助下执行非阻塞的 SSL 握手流量控制。
- 也能够对来自客户端的 SSL 握手请求作一些有趣的事情,好比拒绝使用 SSLv3 协议的旧的 SSL 客户端,甚至是选择性地拒绝。
- 由 lua-resty-core 库提供的 ngx.ssl 和 ngx.ocsp Lua 模块在这种上下文中特别有用。可使用这两个 Lua 模块提供的 Lua API 来操做 SSL 证书链和私钥,以启动当前 SSL 链接。
- 可是,当 NGINX/OpenSSL 经过 SSL 会话 ID 或当前 SSL 链接的 TLS 会话 ticket 成功地恢复 SSL 会话时,这个 Lua 处理程序根据没有运行。也就是说,这个 Lua 处理程序仅在 Nginx 开始完整 SSL 握手时运行。
- 下面是一个使用 ngx.ssl 模块同时进行的简单的示例:
server {
listen 443 ssl;
server_name test.com;
ssl_certificate_by_lua_block {
print("About to initiate a new SSL handshake!")
}
location / {
root html;
}
}
- 注意,即便你根本不使用此静态证书和私钥,你也须要配置 ssl_certificate 和 ssl_certificate_key 指令。这用于知足 Nginx 配置的占位符,不然在启动 Nginx 时会看到如下错误:
nginx: [emerg] no ssl configured for the server
ssl_certificate_by_lua_file
语法:ssl_certificate_by_lua_file <path-to-lua-script-file>
上下文:server
阶段:在 SSL 握手以前
- 等价于 ssl_certificate_by_lua_block,若给定一个相似 foo/bar.lua 的相对路径,则该路径将会被转变为相对 server prefix(由 Nginx 启动时经过 -p PATH 选项指定) 的绝对路径。
2. Nginx API for Lua
ngx.arg
语法:val = ngx.arg[index]
上下文:set_by_lua*, body_filter_by_lua*
- 当在 set_by_lua* 指令的上下文中使用它时,该表是只读的,而且保存配置指令的输入参数:
value = ngx.arg[n]
示例:缓存
location /foo {
set $a 32;
set $b 56;
set_by_lua $sum
'return tonumber(ngx.arg[1]) + tonumber(ngx.arg[2])'
$a $b;
echo $sum;
}
输出为 88,即 32 和 56 的总和。安全
- 当在 body_filter_by_lua* 的上下文中使用该表时,第一个元素将输入数据块保存到 output filter code 中,第二个参数保存指示整个输出数据流结束的 "eof" 标志的布尔标志。
- 传递给下游 Nginx 输出过滤器的数据块和 "eof" 标志也能够经过将值直接分配给相应的表元素来覆盖。当将 ngx.arg[1] 设置为 nil 或空的 lua 字符串值时,数据块将不会被传递到下游 Nginx 的输出过滤中。