Skip to content

Latest commit

 

History

History
251 lines (180 loc) · 8.09 KB

rewrite_by_lua.md

File metadata and controls

251 lines (180 loc) · 8.09 KB

rewrite_by_lua

语法: 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 12set $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";
 ?  }

因为 ifrewrite_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_modulerewrite指令来改变 URI 并发起内部重定向,那么在当前 location 内任何有序的rewrite_by_luarewrite_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:

rewrite_by_lua

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.

Back to TOC