语法: rewrite_by_lua <lua-script-str>
环境: http, server, location, location if
阶段: rewrite tail
作为一个重写阶段的处理程序,为每个请求执行由<lua-script-str>
指定的 Lua 代码。
这些 Lua 代码可以调用全部 API,并作为一个新的协程,在一个独立的全局环境中执行(就像一个沙盒)。
注意这个处理过程总是在标准ngx_http_rewrite_module的 后 面。所以下面的示例可以按照预期执行:
location /foo {
set $a 12; # create and initialize $a
set $b ""; # create and initialize $b
rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1';
echo "res = $b";
}
因为 set $a 12
和 set $b ""
的执行都在rewrite_by_lua的前面。
另一方面,下面的示例是不能按照预期执行:
? location /foo {
? set $a 12; # create and initialize $a
? set $b ''; # create and initialize $b
? rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1';
? if ($b = '13') {
? rewrite ^ /bar redirect;
? break;
? }
?
? echo "res = $b";
? }
因为 if
是rewrite_by_lua之 前 执行的,尽管在配置中它被放到rewrite_by_lua后面。
正确的处理方式应该是这样:
location /foo {
set $a 12; # create and initialize $a
set $b ''; # create and initialize $b
rewrite_by_lua '
ngx.var.b = tonumber(ngx.var.a) + 1
if tonumber(ngx.var.b) == 13 then
return ngx.redirect("/bar");
end
';
echo "res = $b";
}
注意,ngx_eval模块可以近似的使用rewrite_by_lua。例如:
location / {
eval $res {
proxy_pass http://foo.com/check-spam;
}
if ($res = 'spam') {
rewrite ^ /terms-of-use.html redirect;
}
fastcgi_pass ...;
}
在ngx_lua中可以这样实施:
location = /check-spam {
internal;
proxy_pass http://foo.com/check-spam;
}
location / {
rewrite_by_lua '
local res = ngx.location.capture("/check-spam")
if res.body == "spam" then
return ngx.redirect("/terms-of-use.html")
end
';
fastcgi_pass ...;
}
如同其他重写阶段处理, rewrite_by_lua在子请求中也执行的。
注意,在rewrite_by_lua处理内部,当调用ngx.exit(ngx.OK)
时,nginx请求将继续下一阶段的内容处理。要在rewrite_by_lua处理中终结当前请求,调用ngx.exit,成功的请求设定 status >= 200 (ngx.HTTP_OK
) 并 status < 300 (ngx.HTTP_SPECIAL_RESPONSE
),失败的请求设定ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
(或其他相关的)。
如果使用了ngx_http_rewrite_module的rewrite指令来改变 URI 并发起内部重定向,那么在当前 location 内任何有序的rewrite_by_lua 或 rewrite_by_lua_file代码都将不被执行。例如:
location /foo {
rewrite ^ /bar;
rewrite_by_lua 'ngx.exit(503)';
}
location /bar {
...
}
Here the Lua code ngx.exit(503)
will never run. This will be the case if rewrite ^ /bar last
is used as this will similarly initiate an internal redirection. If the break
modifier is used instead, there will be no internal redirection and the rewrite_by_lua
code will be executed.
rewrite_by_lua
代码将永远在 rewrite
请求处理阶段后面,除非rewrite_by_lua_no_postpone配置开启。
English source:
syntax: rewrite_by_lua <lua-script-str>
context: http, server, location, location if
phase: rewrite tail
Acts as a rewrite phase handler and executes Lua code string specified in <lua-script-str>
for every request.
The Lua code may make API calls and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox).
Note that this handler always runs after the standard ngx_http_rewrite_module. So the following will work as expected:
location /foo {
set $a 12; # create and initialize $a
set $b ""; # create and initialize $b
rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1';
echo "res = $b";
}
because set $a 12
and set $b ""
run before rewrite_by_lua.
On the other hand, the following will not work as expected:
? location /foo {
? set $a 12; # create and initialize $a
? set $b ''; # create and initialize $b
? rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1';
? if ($b = '13') {
? rewrite ^ /bar redirect;
? break;
? }
?
? echo "res = $b";
? }
because if
runs before rewrite_by_lua even if it is placed after rewrite_by_lua in the config.
The right way of doing this is as follows:
location /foo {
set $a 12; # create and initialize $a
set $b ''; # create and initialize $b
rewrite_by_lua '
ngx.var.b = tonumber(ngx.var.a) + 1
if tonumber(ngx.var.b) == 13 then
return ngx.redirect("/bar");
end
';
echo "res = $b";
}
Note that the ngx_eval module can be approximated by using rewrite_by_lua. For example,
location / {
eval $res {
proxy_pass http://foo.com/check-spam;
}
if ($res = 'spam') {
rewrite ^ /terms-of-use.html redirect;
}
fastcgi_pass ...;
}
can be implemented in ngx_lua as:
location = /check-spam {
internal;
proxy_pass http://foo.com/check-spam;
}
location / {
rewrite_by_lua '
local res = ngx.location.capture("/check-spam")
if res.body == "spam" then
return ngx.redirect("/terms-of-use.html")
end
';
fastcgi_pass ...;
}
Just as any other rewrite phase handlers, rewrite_by_lua also runs in subrequests.
Note that when calling ngx.exit(ngx.OK)
within a rewrite_by_lua handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a rewrite_by_lua handler, calling ngx.exit with status >= 200 (ngx.HTTP_OK
) and status < 300 (ngx.HTTP_SPECIAL_RESPONSE
) for successful quits and ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
(or its friends) for failures.
If the ngx_http_rewrite_module's rewrite directive is used to change the URI and initiate location re-lookups (internal redirections), then any rewrite_by_lua or rewrite_by_lua_file code sequences within the current location will not be executed. For example,
location /foo {
rewrite ^ /bar;
rewrite_by_lua 'ngx.exit(503)';
}
location /bar {
...
}
Here the Lua code ngx.exit(503)
will never run. This will be the case if rewrite ^ /bar last
is used as this will similarly initiate an internal redirection. If the break
modifier is used instead, there will be no internal redirection and the rewrite_by_lua
code will be executed.
The rewrite_by_lua
code will always run at the end of the rewrite
request-processing phase unless rewrite_by_lua_no_postpone is turned on.