[code.openresty] Openresty指令集-上

指令集

Nginx和Lua最基本的构建块脚本是指令集。指令集用于确定什么时候用户的Lua代码运行和结果将会被怎么使用。下面的图显示指令集的执行顺序。

Lua Nginx 模块指令集

lua_capture_error_log

语法: lua_capture_error_log size

默认:

上下文: http

用户捕获所有的nginx错误日志消息数据(并不是由本模块或者nginx http子系统产生的,而是所有的)指定size的缓冲区而不使用文件或磁盘。

你可以在size值中使用计量单位如km,如:

    lua_capture_error_log 100k;

根据经验来说,4kb缓冲区通常可以容纳大约20个典型错误日志消息。所以自己算一下吧!

这个缓冲区永远不增长。如果它满了,新的错误日志消息会在这个缓冲区内替代最老的那个。

缓冲区的大小必须大于单个错误日志消息的最大长度(在OpenResty里是4k,在一般的Nginx里是2k)。

你可以在Lua中通过lua-resty-core库的ngx.errlog模块的
get_logs()方法来读取缓冲区中的消息。这个Lua API方法将会返回捕获的错误日志消息并且也移除这些已经从全局捕获缓冲区读取的消息,为新的错误日志数据腾出空间。出于这个原因,如果用户读取缓冲区的错误日志数据够快的话,用户不应该将这个缓冲区配置的太大。

注意,error_log指令指定的日志级别标准的确对这个捕获功能有影响。这个只会捕获不低于在error_log指令中指定的日志级别的日志消息。
用户还仍然可以通过Lua API函数errlog.set_filter_level选择设置一个更高的过滤日志级别。
所以它比静态的error_log指令更加灵活。

值得注意的是,如果在构建OpenResty或Nginx时在./configure中没有附带--with-debug选项,那么是无法捕获调试日志的。同时在构建用于高开销的产品是不提倡开启调试日志。

这个指令首先在v0.10.9版本中被介绍。

lua_use_default_type

语法: lua_use_default_type on | off

默认: lua_use_default_type on

上下文: http,server,location,location if

指定是否使用通过default_type指令指定的MIME类型作为响应头的Content-Type的默认值。如果一个Lua请求处理程序的响应头的类型不想用默认的Content-Type类型,那么禁用这个指令。

这个指令在默认情况下是开启的。

这个指令在v0.9.1版本中被首先介绍。

lua_malloc_trim

语法: lua_malloc_trim <request-count>

默认: lua_malloc_trim 1000

上下文: http

由Nginx内核处理每N个请求后,告诉底层的libc运行时间库释放它缓存的空闲内存给操作系统。默认情况下,N是1000。你可以用你自己的数字配置请求的数量。比较小的数字意味着更加频繁的释放,这可能会导致更高的CPU时间消耗和更小的内存占用。同时比较大的数字通常会导致更少的CPU时间开销和一个相对更大的内存占用。
请根据你自己的使用情况来调整数字。

将参数配置为0会基本上完全关闭内存整理。

  lua_malloc_trim 0; # 完全关闭内存整理

当前实现中使用Nginx日志处理程序来做请求计数。所以在nginx.conf里出现log_subrequest on指令可能会在包含子请求的时候让计数更快。默认情况下,只统计主请求(main request)。

注意这个指令并会影响LuaJIT的分配器基于mmap系统调用的内存空间。

这个指令在v0.10.7版本中被首先介绍。

lua_code_cache

语法: lua_code_cache on | off

默认: lua_code_cache on

上下文: http,server,location,location if

*_by_lua_file指令(如set_by_lua_file
content_by_lua_file)和Lua模块中启用或者禁用Lua代码缓存。

当设置off时,每个通过ngx_lua处理的缓存会运行在一个单独的Lua VM实例,从0.9.3版本开始。所以在set_by_lua_file,
content_by_lua_file, access_by_lua_file,等等引用的Lua文件将不会被缓存并且所有的被使用到的Lua模块将会被从头开始加载。有了这个,开发人员可以采用edit-and-refresh方法。

不过请注意,在nginx.conf里写的内联Lua代码例如这些set_by_lua, content_by_lua,
access_by_lua,和rewrite_by_lua指定的,在你修改了你nginx.conf文件里的内联Lua代码之后将不会被更新,这是因为只有Nginx配置文件解析器能正确解析nginx.conf文件并且唯一的方法是通过发送一个HUP信号来重新加载配置文件或者直接重启Nginx。

即使是启用了代码缓存,在*_by_lua_file中通过dofileloadfile加载的Lua文件不能被缓存(除非你自己缓存那些结果)。通常你既可以使用init_by_lua或者 init_by_lua_file 指令来加载所有这些文件或者把这些Lu文件当做真正的Lua模块并且通过require加载他们。

在Apachemod_lua模块下,ngx_lua模块并不支持stat模式可用。

在生产模式下,强烈不建议禁用Lua代码缓存,并且这个只能在开发时候使用,这是因为它对整体性能有很大的负面影响。例如,在禁用Lua代码缓存之后,“hello world”的Lua实例的性能表现会下降一个数量级。

lua_regex_cache_max_entries

语法: lua_regex_cache_max_entries <num>

默认: lua_regex_cache_max_entries 1024

上下文: http

指定在工作进程级别编译的正则表达式缓存允许的最大数量的条目。

ngx.re.match, ngx.re.gmatch, ngx.re.sub, 和 ngx.re.gsub中使用到的正则表达式会被缓存,如果指定了正则表达式选项o(例如,compile-once flag)

默当到达了这个限制是,默认允许的条目数量是1024,新的正则表达式将不会被缓存(如果没有指定o选项)并且这里会有一次,且只有一次,在error.log文件中的警告信息:

2011/08/27 23:18:26 [warn] 31997#0: *1 lua exceeding regex cache max entries (1024), ...

如果你通过加载resty.core.regex模块(或者仅仅resty.core模块)来使用ngx.re.*实现lua-resty-core,那么这里使用的正则表达式缓存会是一个LRU缓存。

在动态生成的正则表达式中不要启用o选项(并且/或 ngx.re.subngx.re.gsubreplace字符串参数),这会产生无限的变化以避免触及指令的限制。

lua_regex_match_limit

语法: lua_regex_match_limit <num>

默认: lua_regex_match_limit 0

上下文: http

在执行ngx.re API指定被PCRE库使用到的"match limit"。根据PCRE使用手册,"这个限制 ... 对可以发生的回溯的限制数量有影响。"

当限制被命中,在Lua里面的ngx.re API方法会返回 "pcre_exec() failed: -8"错误字符串。

当设置限制为0,编译PCRE库会使用默认的“match limit”。并且这是这个指令默认的值。

这个指令在v0.8.5版本中被首先介绍。

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 or ${prefix}可以在搜索路径字符串中使用来表明server prefix的路径,而这个路径通常是在启动Nginx服务器时通过-p PATH命令号选项确定的。

lua_package_cpath

语法: lua_package_cpath <lua-style-cpath-str&gt

默认: LUA_CPATH环境变量或者Lua默认编译的内容

上下文: http

设定在set_by_lua,
content_by_lua和其他指令的脚本中使用到的Lua C模块的搜索路径。这个cpath路径在标准Lua cpath形式,并且;;可以被用来表示原始的的cpath。

v0.5.0rc29版本开始,特殊符号 $prefix or ${prefix}可以在搜索路径字符串中使用来表明server prefix的路径,而这个路径通常是在启动Nginx服务器时通过-p PATH命令号选项确定的。

init_by_lua

语法: init_by_lua <lua-script-str>

上下文: http

时期: loading-config

注意v0.9.17版本之后不建议使用这个指令。使用 init_by_lua_block指令来代替。

当Nginx主进程(如果有的话)加载Nginx配置文件时,在全局Lua VM级别通过指定参数<lua-script-str>来运行Lua代码。

当Nginx收到HUP信号并且开始重新加载配置文件,这个Lua VM也会被重新创建并且在新的Lua VM中init_by_lua会被重新执行。如果 lua_code_cache 指令是关闭的(默认开启),这个init_by_lua处理器会在每个请求都运行。这是因为在这个特殊模式下,针对每个request请求,都会创建一个单独的Lua VM。

通常情况下你可以注册(true)Lua全局变量或者通过这个钩子模块在服务器启动时预装载Lua模块。这里是预装载Lua模块的例子:


  init_by_lua 'cjson = require "cjson"';

  server{
      location = /api{
          content_by_lua_block {
              ngx.say(cjson.encode({dog = 5,cat = 6}))
          }
      }
  }

你也可以在这个阶段初始化lua_shared_dict共享存储器。这里是一个例子:


    lua_shared_dict dogs 1m;

    init_by_lua '
        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共享存储区在配置文件重新加载时(例如:通过HUP信号)不会被清除。所以如果你想在这个阶段的init_by_lua代码里面重新初始化共享存储器,那么你只需要在共享存储器里面设置一个自定义标记并且一直在你的init_by_lua代码里面检查这个标记。

因为此上下文的Lua代码在Nginx forks其工作进程之前执行(若有的话),这里加载的数据或代码会享受很多操作系统在所有工作进程中提供的Copy-on-write (COW)特性,从而节约了大量的内存。

要在这个上下文中中初始化你自己的Lua全局变量,这是因为使用Lua全局变量会有性能损失并且会导致全局命名空间污染(参阅Lua Variable Scope章节查看详情)。推荐的方法是使用适当的Lua module文件(但是不要使用标准Lua方法module() 来定义Lua模块因为它也会污染全局命名空间)并且调用require()init_by_lua或其他上下文中加载你自己的模块文件。(require() 会缓存被加载的Lua模块到在Lua注册的全局package.loaded表中,所以你的模块在整个Lua VM实例中只会被加载一次)。

在这个上下文中,只有一小部分的Nginx API for Lua是被支持的:

在用户的请求下,在未来更多的Nginx API可能会在此上下文中被支持。

基本上你可以在这个上下文中安全的使用Lua库来做阻塞的I/O,这是因为在服务启动时,阻塞master进程是完全可行的。甚至在配置加载阶段Nginx内核会做阻塞I/O(至少在解决upstream里面的host名称时)。

你应该在Lua代码中非常小心潜在的安全漏洞,这是因为Nginx主进程经常在root账号下启动。

这个指令首先在v0.5.5版本中被介绍。

init_by_lua_block

语法: init_by_lua_block { lua-script }

上下文: http

时期: loading-config

init_by_lua 指令相似,除了这个指令使用一对大括号({})替代Nginx字符串文字(需要特殊字符转义)来包含Lua代码。

例如:


init_by_lua_block{
      print("I need no extra escaping here, for example: \r\nblah")
}

这个指令首先在v0.9.17版本中被介绍。

init_by_lua_file

语法: init_by_lua_file <path-to-lua-script-file>

上下文: http

时期: loading-config

init_by_lua等价,除了被<path-to-lua-script-file>指定的文件包含要被执行的Lua代码或者 Lua/LuaJIT bytecode

当给出的是一个相对地址如foo/bar.lua,他们将会相对于 server prefix 转化为绝对路径, server prefix是在启动Nginx服务器时通过-p PATH命令行参数指定的。

这个指令首先在v0.5.5版本中被介绍。

init_worker_by_lua

语法: init_worker_by_lua <lua-script-str>

上下文: http

时期: starting-worker

注意v0.9.17开始 不建议 使用这个指令。使用init_worker_by_lua_block指令替代。

在Nginx主进程启用时,在每个Nginx工作进程启动时运行指定的Lua代码。当主进程被禁用时,这个钩子将只会在 init_by_lua*之后运行。

这个钩子经常被用来创建每个工作进程常有的定时器(通过ngx.timer.at Lua API),为后端健康检查或者其他日常工作。下面是例子,


    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 no 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 hd1,err = new_timer(delay,check)
          if not hd1 then
              log(ERR,"failed to create timer:",err)
              return
          end
    ';

这个指令首先在v0.9.5版本中被介绍过。

init_worker_by_lua_block

语法: init_worker_by_lua_block { lua-script }

上下文: http

时期: starting-worker

init_worker_by_lua指令相似,除了这个指令将Lua代码直接通过一对大括号({})包含起来,代替Nginx字符串(需要特殊的字符转义)

例如:


    init_worker_by_lua_block {
        print("I need no extra escaping here,for example:\r\nblah")
    }

这个指令首先在v0.9.17版本中被介绍。

init_worker_by_lua_file

语法: init_worker_by_lua_file <lua-file-path>

上下文: http

时期: starting-worker

init_worker_by_lua相似,但是文件路径接受一个Lua源码文件或者Lua字节码文件。

这个指令首先在v0.9.5版本中被介绍。

set_by_lua

语法: set_by_lua $res <lua-script-str> [$arg1 $arg2 ...]

上下文: server,server if,location,location if

时期: rewite

注意v0.9.17版本开始 不建议 使用这个指令。使用 set_by_lua_block指令代替。

<lua-script-str>中指定的可执行的Lua代码和可选参数$arg1 $arg2 ...,并且返回字符串输出给$res。在<lua-script-str>中的代码可以执行 API calls 并且可以从 ngx.arg 表(所以从1开始并且按顺序增加)中检索输入参数。

这个指令是为了执行短、快速运行的代码块,因为在代码执行过程中,Nginx事件循环是被阻塞的。应该避免耗时的代码序列。

这个指令是由注入到定制命令道标准的ngx_http_rewrite_module命令列表来实现的。因为ngx_http_rewrite_module 在他的命令里面并不支持非阻塞I/O,在这个指令中,Lua API需要的暂停当前Lua “light thread”不能工作。

至少在set_by_lua的上下文中下面的这些API方法目前是被禁用的。

另外,注意这个指令一次只能写出一个Nginx变量值。然而,使用ngx.var.VARIABLE 接口是一个可行的解决方案。


    location /foo {
        set $diff ''; # 我们在这里需要已定义$diff变量

        set_by_lua $sum '
            local a = 32
            local b = 56

            ngx.var.diff = a - b; -- 直接写到$diff
            return a + b; -- 正常的返回$sum值
        ';

        echo "sum = $sum,diff = $diff";
    }

这个指令可以和ngx_http_rewrite_module, set-misc-nginx-module, 和 array-var-nginx-module模块的指令自由的组合。所有这些指令会按照他们在配置文件里面显示的相同顺序执行。


    set $foo 32;
    set_by_lua $bar 'return tonumber(ngx.var.foo) + 1';
    set $baz "bar: $bar"; #$bar == “bar:33”

v0.5.0rc29版本开始,在这个指令的<lua-script-str>参数里面直接插入Nginx变量是被禁用的并且因此,dollar符号字符($)可以被直接使用。

这个指令需要ngx_devel_kit模块。

set_by_lua_block

语法: set_by_lua_block $res { lua-script }

上下文: server,server if,location,location if

时期: rewrite

set_by_lua指令相似除了以下这些:

  1. 这个指令通过一对大括号({})将Lua源代码直接包含起来,而不是使用Nginx字符串(需要特殊字符转义),并且
  2. 相比set_by_lua指令,这个指令并不支持Lua脚本之后的额外参数

例如:


  set_by_lua_block $res {return 32 + math.cos(32)}
  # $res 现在有"32.834223360507"或者类似的值

在这个Lua代码块中不需要特殊的转义。

这个指令从v0.9.17版本被首先介绍。

set_by_lua_file

语法: set_by_lua_file $res ≶path-to-lua-script-file> [$arg1 $arg2 ...]

上下文: server,server if,location,location if

时期: rewrite

set_by_lua等价,除了在<path-to-lua-script-file>中指定包含Lua代码的文件,或者,从v0.5.0rc32版本,Lua/LuaJIT bytecode被排除了。

在这个指令的<path-to-lua-script-file>参数字符串中,Nginx变量插入是支持的。但是必须特别注意注入攻击。

当给出一个类似foo/bar.lua的相对路径,它们会相对server prefix路径来变成绝对路径,这个变量是通过在启动Nginx服务器时在命令行中定义的-p PATH参数定义的。

当Lua代码缓存被打开后(默认情况下),用户的代码会在第一次请求的时候被加载并且被缓存并且再Lua源码文件被修改后Nginx配置必须被重新加载。

在开发时可以临时的将Lua代码缓存通过在nginx.conf里转换lua_code_cacheoff禁用掉,从而避免重启Nginx。

这个指令需要ngx_devel_kit模块。

content_by_lua

语法: content_by_lua <lua-script-str>

上下文: location,location if

时期: content

注意v0.9.17版本开始,不建议 使用这个指令,使用 content_by_lua_block指令代替。

作为一个“内容处理程序”执行并且在每个请求中执行<lua-script-str>中指定的Lua代码字符串。
其中的Lua代码可以执行API calls并且将会在一个独立的全局环境(例如,一个沙箱)中作为一个新的子协同程序被执行。

不要在同一个location中使用这个指令和其他内容处理程序指令。例如:这个指令和proxy_pass 指令不能再同一个location中被同时使用。

content_by_lua_block

语法: content_by_lua_block { lus-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版本开始被介绍。

content_by_lua_file

语法: content_by_lua_file <path-to-lua-script-file>

上下文: locaiton,location if

时期: content

content_by_lua相似,除了<path-to-lua-script-file>指定包含Lua代码的文件,或者,从v0.5.0rc32版本开始,Lua/LuaJIT bytecode 被排除了。

Nginx变量可以在<path-to-lua-script-file>字符串中使用以提供灵活性。然而这会带来一些风险,不被推荐。

当给出一个相对路径例如foo/bar.lua时,它们会相对server prefix路径转换成为绝对路径,server prefix在Nginx服务器启动时通过-p PATH参数指定。

当Lua代码缓存被启用(默认),在第一次请求时用户代码会被加载并缓存并且当Lua源文件被修改后Nginx配置必须被重新加载。

在开发时可以临时的将Lua代码缓存通过在nginx.conf里转换lua_code_cacheoff禁用掉,从而避免重启Nginx。

为了动态调度,文件路径中支持Nginx变量,例如:


    # 注意:内容中的nginx变量必须被小心的过滤掉。
    # 否则会有严重的安全风险。
    location ~ ^/app/([-_a-zA-Z0-9/]+) {
        set $path $1;
        content_by_lua_file /path/to/lua/app/root/$path.lua;
    }

但是要非常小心恶意用户输入并且总要仔细验证或过滤掉用户提供的路径部分。

rewrite_by_lua

语法: rewrite_by_lua <lua-script-str>

上下文: http,server,location,location if

时期: rewrite tail

注意 这个指令在v0.9.17版本之后 不建议 被使用。使用rewrite_by_lua_block指令代替。

作为rewite阶段处理程序使用并且为每个请求执行<lua-script-str>中的Lua代码字符串。Lua代码可以执行 API calls 并且会在一个独立的全局环境(如:沙箱)中作为一个新的子协同程序执行。

注意这个处理程序经常在标准ngx_http_rewrite_module 之后 执行,所以下面的会按照预期工作:


    location /foo {
        set $a 12; # 创建并初始化$a
        set $b ""; # 创建并初始化$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";
?  }

这是因为 if会在rewrite_by_lua 之前 执行,即使在配置文件里面它被放置在rewrite_by_lua之后。

正确实现如下:


    location /foo {
        set $a 12; # 创建并实例化 $a
        set $b ''; # 创建并实例化 $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/ehck-span;
        }

        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阶段处理程序一样,rewrite_by_lua同样也在子请求中运行。

注意当在rewrite_by_lua处理程序里面调用ngx.exit(ngx.OK)时,nginx内容处理程序的请求处理控制流仍然能继续。要终止从rewrite_by_lua处理器内部的当前请求,以status >= 200(ngx.HTTP_OK) 和 status < 300(ngx.HTTP_SPECIAL_RESPONSE)调用ngx.exit来处理成功退出,使用ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)(或其朋友)处理失败。

如果ngx_http_rewrite_modulerewrite指令被用来更改URI和启动location re-lookups(内部重定向),那么着当前location里的任何 rewrite_by_lua或者rewrite_by_lua_file 代码序列将不会被执行。例如:


    location /foo {
        rewite ^ /bar;
        rewrite_by_lua 'ngx.exit(503)';
    }
    location /bar {
        ...
    }

这里的Lua代码ngx.exit(503)将永远不会被执行。这是因为如果rewrite ^ /bar last被使用了的话这里将会启动一个内部重定向。如果使用break修饰语,这里将不会有内部重定向并且rewrite_by_lua代码块将会被执行。

这个rewrite_by_lua代码将会一直在rewrite请求处理阶段之后执行除非rewrite_by_lua_no_postpone被开启。

rewrite_by_lua_block

语法: rewrite_by_lua_block { lua-script }

上下文: http,server,location,location if

时期: rewrite tail

rewrite_by_lua指令相似除了这个指令通过一对大括号({})来直接包含Lua代码而不是使用Nginx字符串(需要特殊字符转义)

例如,


    rewrite_by_lua_block {
        do_something("hello, world!\nhiya\n")
    }
  

这个指令首先从 v0.9.17版本被介绍。

rewrite_by_lua_file

语法: rewrite_by_lua_file <path-to-lua-script-file>

上下文: http,server,location,location if

时期: rewrite tail

rewrite_by_lua等价,除了<path-to-lua-script-file>指定包含Lua代码的文件,或者,从v0.5.0rc32版本,Lua/LuaJIT bytecode被排除了。

Nginx变量可以在 <path-to-lua-script-file>字符串中被使用以提供灵活性。但是这会增加一些风险并且一般不推荐。

当给出以一个相对地址如foo/bar.lua,它们会相对server prefix地址转成绝对地址,server prefix在Nginx服务器启动时通过命令行选项-p PATH来定义。

当Lua代码缓存被开启(默认),用户的代码会在第一次请求时被加载并且被缓存,如果Lua代码文件被修改了那么Nginx配置必须被重新加载。在开发时,可以临时的关闭Lua代码缓存来避免重启Nginx,通过将nginx.conf里的lua_code_cache转换为off

rewrite_by_lua_file代码会一直在rewrite请求处理阶段结束后执行除非rewrite_by_lua_no_postpone被开启。

为了在content_by_lua_file里支持动态调度,文件路径中支持Ngixn变量。

access_by_lua

语法: access_by_lua <lua-script-str>

上下文: http,server,location,location if

时期: access tail

注意v0.9.17版本之后 不建议 使用这个指令。使用access_by_lua_block指令代替。

作为访问阶段处理程序执行并且为每个请求执行<lua-script-str>指定的Lua代码。
Lua代码可以执行API calls并且它在一个独立的全局环境(如:沙箱)里作为一个子协同程序执行。

注意这个处理器一直在标准的ngx_http_access_module 之后 运行。所以下面的会按照预期执行:


    location / {
        deny 192.168.1.1;
        allow 192.168.1.0/24;
        allow 10.1.1.0/16;
        deny all;

        access_by_lua '
            local res = ngx.location.capture("/mysql",{...})
            ...
        ';

        # proxy_pass/fastcgi_pass/...
    }

就是说,如果一个客户端IP在黑名单内,它被在MySQL查询之前被阻止,对更加复杂的身份认证是用access_by_lua执行的。

注意可以使用access_by_lua来近似ngx_auth_request模块。


    location / {
        auth_request /auth;
        # proxy_pass/fastcgi_pass/postgres_pass/...
    }
  

可以被ngx_lua实现如下:


    location / {
        access_by_lua '
            local res = ngx.location.capture("/auth")

            if res.status == ngx.HTTP_OK then
                return
            end

            if res.status == ngx.HTTP_FORBIDDEN then
                ngx.exit(res.status)
            end

            ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
        ';

        # proxy_pass/fastcgi_pass/postgres_pass/...
    }

正如其他访问阶段处理程序,access_by_lua不会 在子请求中被执行。

注意当在access_by_lua处理程序里面调用ngx.exit(ngx.OK)时,nginx内容处理程序的请求处理控制流仍然能继续。要终止从access_by_lua处理器内部的当前请求,以status >= 200(ngx.HTTP_OK) 和 status < 300(ngx.HTTP_SPECIAL_RESPONSE)调用ngx.exit来处理成功退出,使用ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)(或其朋友)处理失败。

v0.9.20版本开始,你可以使用access_by_lua_no_postpone指令来控制在Nginx的"accesss"请求处理阶段什么时候运行这个处理器。

access_by_lua_block

语法: access_by_lua_block { lua-script }

上下文: http,server,location,location if

阶段: access tail

access_by_lua指令相似,除了这个指令通过一对大括号({})直接包含其中的Lua代码,而不是使用Nginx字符串(需要特殊字符转码)

例如:


    access_by_lua_block{
        do_something("hello, world!\nhiya\n")
    }
    

这个指令首先在v0.9.17版本中被介绍。

access_by_lua_file

语法: access_by_lua_file <path-to-lua-script-file>

上下文: http,server,location,location if

阶段: access tail

access_by_lua等价,除了<path-to-lua-script-file>指定包含Lua代码的文件,或者,从 v0.5.0rc32版本开始,Lua/LuaJIT bytecode 被排除了。

<path-to-lua-script-file>字符串中可以使用Nginx变量以提供灵活性。然而这回增加风险而且一般不建议使用。

当给出一个类似foo/bar.lua的相对路径,它们会相对server prefix路径来变成绝对路径,这个变量是通过在启动Nginx服务器时在命令行中定义的-p PATH参数定义的。

当Lua代码缓存被打开后(默认情况下),用户的代码会在第一次请求的时候被加载并且被缓存并且再Lua源码文件被修改后Nginx配置必须被重新加载。

在开发时可以临时的将Lua代码缓存通过在nginx.conf里转换lua_code_cacheoff禁用掉,从而避免重启Nginx。

content_by_lua_file中为了实现动态调度,文件路径里面支持Nginx变量。

header_filter_by_lua

语法: header_filter_by_lua <lua-script-str>

上下文 http,server,location,location if

时期 output-header-filter

注意v0.9.17版本之后 不建议 使用该指令。使用header_filter_by_lua_block指令代替

使用<lua-script-str>指定的Lua代码来定义一个输出header的过滤器。

注意在此上下文中下面的API方法目前是禁用的:

这里是在我们的Lua header过滤器中重写响应header的一个例子(如果为空则是添加)


  location / {
      proxy_pass http://mybackend;
      header_filter_by_lua 'ngx.header.Foo = "blah"';
  }

这个指令首先在v0.2.1rc20版本中被介绍。

header_filter_by_lua_block

语法: header_filter_by_lua_block { lua-script }

上下文: http,server,location,location if

时期: output-header-filter

header_filter_by_lua指令相似除了这个指令将Lua代码直接包含在一对大括号({})之内而不是Nginx字符串(需要特殊的字符转码)。

例如,


    header_filter_by_lua_block{
      ngx.header["content-length"] = nil
    }

这个指令首先在 v0.9.17版本中被介绍。

header_filter_by_lua_file

语法: header_filter_by_lua_file <path-to-lua-script-file>

时期: http,server,location,location if

阶段: output-header-filter

header_filter_by_lua等价,除了通过<path-to-lua-script-file指定的文件包含Lua代码,或者,从 v0.5.0rc32 版本, Lua/LuaJIT bytecode被排除了。

当给定一个相对路径如foo/bar.lua,它们会相对server prefix转化为绝对路径,server prefix路径在Nginx服务器启动时通过命令行里面的-p PATH参数指定。

这个指令在v0.2.1rc20版本时被首先介绍。

body_filter_by_lua

语法: body_filter_by_lua <lua-script-str>

上下文: http,server,location,location if

时期: output-body-filter

注意:v0.9.17版本开始 不建议 使用这个指令。使用body_filter_by_lua_block指令来代替。

通过<lua-script-str>指令指定的Lua代码定义一个输出body过滤器

输出数据块通过ngx.arg[1]来传递(作为一个Lua字符串值)并且标志响应body数据流结束的"eof"标记通过ngx.arg[2]来传递(作为一个Lua boolean值)。

在幕后,“eof”标记就是在Nginx链条的缓冲区的last_buf(在主请求中)或者last_in_chain(在子请求中)标记。(在 v0.7.14版本之前,"eof"标记在所有的子请求中不起效)

输出数据流可以通过运行下面的Lua语句立即中止:

    return ngx.ERROR

这个将截断响应体并且通常情况下导致不完整也无效的响应。

Lua代码可以将它自己修改过的输入数据块传送给下游的Nginx输出body过滤器中,通过用一个Lua字符串或包含字符串的Lua table重写ngx.arg[1]。例如:在response body里面转换所有的小写字母,我们可以这样写:


    location / {
        proxy_pass http://mybackend;
        body_filter_by_lua 'ngx.arg[1] = string.upper(ngx.arg[1])';
    }

当设置为nil或者一个空Lua字符串给ngx.arg[1],没有数据块会被传输到Nginx下游的输出过滤器。

同样的,新的"eof"标记可以通过设置一个boolean值给ngx.arg[2]来指定。例如:


    location /t {
        echo hello world;
        echo hiya globe;
        body_filter_by_lua '
              local chunk = ngx.arg[1]
              if string.match(chunk,"hello") then
                    ngx.arg[2] = true -- new eof
              end

              -- just throw away any remaining chunk data
              ngx.arg[1] = nil
        ';
    }

然后 GET /t只会返回输出:

hello world

也就是说,当body过滤器发现一块包含单词"hello",那么它会立即将"eof"标记设置为true,导致了一个截断但仍然有效的回复。

Lua代码有时会改变响应的body的长度,那么它应该经常的在头过滤器中清除Content-Length响应头(如果可能的话)来强制流输出,例如:

    location /foo {
          # fastcgi_pass/proxy_pass/...

          header_filter_by_lua_block { ngx.header.content_length = nil}
          body_filter_by_lua 'ngx.arg[1] = string.len(ngx.arg[1]) .. "\\n"';
    }

注意在此上下文中下面的API方法目前是被禁用的,这是由于目前Nginx输出过滤器当前实现的的限制。

Nginx输出过滤器可能在一个请求中被调用多次,因为response body可能被分段传送。因此,这个指令指定的Lua代码可能也会在一个HTTP request的生命周期中被执行多次。

这个指令首先从v0.5.0rc32版本被介绍。

body_filter_by_lua_block

语法: body_filter_by_lua_block { lua-script-str }

上下文: http,server,location,location if

时期: output-body-filter

body_filter_by_lua指令相似除了这个指令将Lua代码直接包含在一对大括号 ({}) 里面而不是Nginx字符串(需要特殊字符转码)

例如,


    body_filter_by_lua_block{
          local data,eof = ngx.arg[1],ngx.arg[2]
    }

这个指令首先在 v0.9.17版本中被介绍。

body_filter_by_lua_file

语法: body_filter_by_lua_file <path-to-lua-script-file>

上下文: http,server,location,location if

时期: output-body-filter

body_filter_by_lua等价,除了通过<path-to-lua-script-file>指定的文件包含Lua代码,或者,从v0.5.0rc32版本开始, Lua/LuaJIT bytecode被排除掉了。

当给出了一个相对地址如 foo/bar.lua,他们会相对server prefix将其转换为绝对地址,server prefix地址通过在启动Nginx服务器时通过命令行里面的-p PATH指定。

这个指令在v0.5.0rc32版本中被首先介绍。

推荐阅读更多精彩内容