热门搜索 :
考研考公
您的当前位置:首页正文

[code.openresty] Openresty Nginx

来源:东饰资讯网

Nginx API for Lua

介绍

各种各样的 *_by_lua_by_lua_block*_by_lua_file配置指令在nginx.conf文件中作为Lua API的网关。下面描述的Nginx Lua API只能在这些配置指令上下文中的用户Lua代码中被调用。

这个API是通过两个标准包ngxndk的形式暴露给Lua。这些包都是在ngx_lua的默认全局范围内并且在ngx_lua指令中总是可用的。

这个包可以像下面这样引入外部Lua模块:


      local say = ngx.say

      local _M = {}

      function _M.foo(a)
          say(a)
      encode_args

      return _M

直接在外部Lua模块require包也是可行的:


    local ngx = require "ngx"
    local ndk = require "ndk"

require这些包的能力是在v0.2.1rc19版本中被介绍的。

ngx.arg

语法: val = ngx.arg[index]

上下文: set_by_luabody_filter_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;
        }

这将会写出883256的和。

传递到下游Nginx输出过滤器的数据块和“eof”标记也可以被复写然后直接赋值给相应表元素。当被设置为nil或者一个空Lua字符串值给ngx.arg[1],没有数据块将会被传递给下游的Nginx过滤器。

ngx.var.VARIABLE

语法: ngx.var.VAR_NAME

上下文: set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua,header_filter_by_lua,body_filter_by_lua,log_by_lua*

读和写Nginx变量值


      value = ngx.var.some_nginx_variable_name
      ngx.var.some_nginx_variable_name = value

注意只有已经定义的Nginx变量可以被写入。例如:


    location /foo {
        set $my_var ''; # this line is required to create $my_var at config time
        content_by_lua_block {
            ngx.var.my_var = 123;
            ...
        }
    }

也就是说,Nginx无法创建动态变量。

Nginx正则表达式组捕获变量$1$2$3,等等,也可以被这个接口读取,通过ngx.var[1],ngx.var[2],ngx.var[3]等等写入。

设置ngx.var.Foonil值会清除$FooNginx变量。

      ngx.var.args = nil

注意 当读取Nginx变量时,Nginx会在每个请求内存池分配内存而且只会在请求终止后释放。所以当你需要在你的Lua代码里面从多次读取一个Nginx变量,以自己的变量来缓存Nginx变来那个,例如,


  local val = ngx.var.some_var
  -- use the val repeatedly later

没有定义域的Nginx变来那个和nil是等价的,而未初始化的(但是已经定义了)Nginx变量和一个空的Lua字符串是等价的。

这个API需要一个相对昂贵的元方法调用并且建议在热代码路径中避免使用它。

Core constants

上下文: init_by_lua,set_by_lua,rewrite_by_lua,access_by_lua,content_by_luaheader_filter_by_lua,body_filter_by_lua,log_by_lua,ngx.timer.,balancer_by_lua,ssl_certificate_by_lua,ssl_session_fetch_by_luassl_session_store_by_lua**


      ngx.OK(0)
      ngx.ERROR (-1)
      ngx.AGAIN (-2)
      ngx.DONE (-4)
      ngx.DECLINED (-5)


    ngx.null

这个ngx.DECLINED常量首先在v0.5.0rc19版本中被介绍。

HTTP method constants

上下文: init_by_lua,set_by_lua,rewrite_by_lua,access_by_lua,ccontent_by_lua,header_filter_by_lua,body_filter_by_lua,log_by_lua,ngx.timer.balancer_by_lua,ssl_certificate_by_luassl_session_fetch_by_luassl_session_store_by_lua*


    ngx.HTTP_GET
    ngx.HTTP_HEAD
    ngx.HTTP_PUT
    ngx.HTTP_POST
    ngx.HTTP_DELETE
    ngx.HTTP_OPTIONS (added in the v0.5.0rc24 release)
    ngx.HTTP_MKCOL (added in the v0.8.2 release)
    ngx.HTTP_COPY (added in the v0.8.2 release)
    ngx.HTTP_MOVE (added in the v0.8.2 release)
    ngx.HTTP_PROPFIND (added in the v0.8.2 release)
    ngx.HTTP_LOCK (added in the v0.8.2 release)
    ngx.HTTP_UNLOCK  (added in the v0.8.2 release)
    ngx.HTTP_PATCH  (added in the v0.8.2 release)
    ngx.HTTP_TRACE  (added in the v0.8.2 release)

HTTP status constants

上下文: init_by_lua, set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua, ngx.timer., balancer_by_lua, ssl_certificate_by_lua, ssl_session_fetch_by_lua, ssl_session_store_by_lua*


    value = ngx.HTTP_CONTINUE (100)  (first added in the v0.9.20 release)
    value = ngx.HTTP_SWITCHING_PROTOCOLS (101)  (first added in the v0.9.20 release)
    value = ngx.HTTP_OK (200)
    value = ngx.HTTP_CREATED (201)
    value = ngx.HTTP_ACCEPTED (202)  (first added in the v0.9.20 release)
    value = ngx.HTTP_NO_CONTENT (204)  (first added in the v0.9.20 release)
    value = ngx.HTTP_PARTIAL_CONTENT (206)  (first added in the v0.9.20 release)
    value = ngx.HTTP_SPECIAL_RESPONSE (300)
    value = ngx.HTTP_MOVED_PERMANENTLY (301)
    value = ngx.HTTP_MOVED_TEMPORARILY (302)
    value = ngx.HTTP_SEE_OTHER (303)
    value = ngx.HTTP_NOT_MODIFIED (304)
    value = ngx.HTTP_TEMPORARY_REDIRECT (307)  (first added in the v0.9.20 release)
    value = ngx.HTTP_BAD_REQUEST (400)
    value = ngx.HTTP_UNAUTHORIZED (401)
    value = ngx.HTTP_PAYMENT_REQUIRED (402)  (first added in the v0.9.20 release)
    value = ngx.HTTP_FORBIDDEN (403)
    value = ngx.HTTP_NOT_FOUND (404)
    value = ngx.HTTP_NOT_ALLOWED (405)
    value = ngx.HTTP_NOT_ACCEPTABLE (406)  (first added in the v0.9.20 release)
    value = ngx.HTTP_REQUEST_TIMEOUT (408)  (first added in the v0.9.20 release)
    value = ngx.HTTP_CONFLICT (409)  (first added in the v0.9.20 release)
    value = ngx.HTTP_GONE (410)
    value = ngx.HTTP_UPGREADE_REQUIRED (426)  (first added in the v0.9.20 release)
    value = ngx.HTTP_TOO_MANY_REQUESTS(429)  (first added in the v0.9.20 release)
    value = ngx.HTTP_CLOSE (444)  (first added in the v0.9.20 release)
    value = ngx.HTTP_ILLEGAL (451)  (first added in the v0.9.20 release)
    value = ngx.HTTP_INTERNAL_SERVER_ERROR (500)
    value = ngx.HTTP_METHOND_NOT_IMPLEMENTED (501)
    value = ngx.HTTP_BAD_GATEWAY (502)  (first added in the v0.9.20 release)
    value = ngx.HTTP_SERVICE_UNAVAILABLE (503)
    value = ngx.HTTP_GATEWAY_TIMEOUT (504)  (first added in the v0.9.20 release)
    value = ngx.HTTP_VERSION_NOT_SUPPORTED (505)  (first added in the v0.9.20 release)
    value = ngx.HTTP_INSUFFICIENT_STORAGE (507)  (first added in the v0.9.20 release)

Nginx log level constants

上下文: init_by_lua, init_worker_by_lua, set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua, ngx.timer., balancer_by_lua, ssl_certificate_by_lua, ssl_session_fetch_by_lua, ssl_session_store_by_lua**


      ngx.STDERR
      ngx.EMERG
      ngx.ALERT
      ngx.CRIT
      ngx.ERR
      ngx.WARN
      ngx.NOTICE
      ngx.INFO
      ngx.DEBUG

print

语法: print(...)

上下文: init_by_lua, init_worker_by_lua, set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua, ngx.timer., balancer_by_lua, ssl_certificate_by_lua, ssl_session_fetch_by_lua, ssl_session_store_by_lua**

将参数值写入ngx error.log文件,以ngx.NOTICE日志级别。

它等价于

  ngx.log(ngx.NOTICE, ...)
``

Lua `nil` 参数是接受的并且结果为文字的`"nil"`字符串同时Lua boolean结果为文字的`"true"`或`"false"`字符串。并且`ngx.null`常量会产生`"null"`字符串输出。

在Nginx核心里面有一个硬编码的`2048`字节限制了错误信息的长度。这个显示包含了尾部的换行和头部的时间戳。如果信息长度超过了限制,Nginx会相应的截断信息文本。这个限制可以被修改,通过编辑 在Nginx源码树中`src/core/ngx.log.h`文件中的`NGX_MAX_ERROR_STR`宏定义。

### ngx.ctx

**上下文:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua**

这个表可以用来存储每个请求上下文中的数据并且有一个和当前请求(正如Nginx变量)完全相同的生命周期。

参考下面的例子,

```nginx

    location /test {
        rewrite_by_lua_block {
            ngx.ctx.foo = 76
        }
        access_by_lua_block {
            ngx.ctx.foo = ngx.ctx.foo + 3
        }
        content_by_lua_block {
            ngx.say(ngx.ctx.foo)
        }
    }

然后GET /test会产生输出

  79

也就是说,ngx.ctx.foo 持续存在request请求的rewrite,access,和content阶段。

每个请求,包含子请求,包含它自己的table副本,例如:


    location /sub {
        content_by_lua_block {
            ngx.say("sub pre:",ngx.ctx.blah)
            ngx.ctx.blah = 32
            ngx.say("sub post:",ngx.ctx.blah)
        }
    }

    location /main {
        content_by_lua_block {
             ngx.ctx.blah = 73
             ngx.say("main pre:",ngx.ctx.blah)
             local res = ngx.location.capture("/sub")
             ngx.print(res.body)
             ngx.say("main post:",ngx.ctx.blah)
        }
    }

然后 GET /main会给出下面的输出


    main pre: 73
    sub pre: nil
    sub post: 32
    main post:73

这里,在子请求中对ngx.ctx.blah的修改并没有影响父请求中的那个。这是因为他们有两个分开的版本的ngx.ctx.blah

内部重定向会摧毁原始请求的ngx.ctx数据(如果可能)并且新的请求会有空的ngx.ctx表,例如:


      location /new {
          content_by_lua_block {
              ngx.say(ngx.ctx.foo)
          }
      }

      location /orig {
          content_by_lua_block {
              ngx.ctx.foo = "hello"
              ngx.exec("/new")
          }
      }

然后 GET /orig会得到


  nil

而不是原始的"hello"值。

任意的数据值,包括Lua闭包和嵌套的表,可以被插入到这个“神奇的”表。它还允许注册自定义的元表。

通过一个新的Lua table来覆盖ngx.ctx也是支持的,例如,


    ngx.ctx = { foo = 32, bar = 54}

这个ngx.ctx查找需要相对昂贵的元方法调用并且它比明确的在你自己的方法参数里面传递当前请求数据相比要慢的多。所以不要滥用这个API来保存你自己方法的参数因为它经常有一些相当的性能影响。


      -- mymodule.lua
      local _M = {}

      -- the following line is bad since ngx.ctx is a per-request
      -- data while this <code>ctx</code> variable is on the Lua module level
      -- and thus is per-nginx-worker.
      local ctx = ngx.ctx

      function _M.main()
          ctx.foo = "bar"
      end

      return _M

使用下面的替代:


    -- mymodule.lua
    local _M = {}

    function _M.main(ctx)
        ctx.foo = "bar"
    end

    return _M

这是,让调用者通过方法参数显示的传递ctx表。

ngx.location.capture

语法: res = ngx.location.capture(uri,options?)

上下文: rewrite_by_lua,access_by_lua,content_by_lua*

使用uri发出一个同步的但是仍然是非阻塞的 Nginx 子请求

Nginx的子请求提供一个强大的的方法来发出一个非阻塞内部请求,到磁盘文件目录配置的其他location,或者任何nginx C模块如ngx_proxy,ngx_fastcgi,ngx_memc,ngx_postgres,ngx_drizzle,甚至ngx_lua本身等等。

还要注意,subrequest模拟HTTP接口,但是没有额外的HTTP流量和IPC。一切在内部工作,高效的,在C级别。

这里有个基本的例子:


    res = ngx.location.capture(uri)

将返回一个Lua表,包含4个插槽:res.status,res.header,res.body,和res.truncated

res.status包含了子请求的响应的响应状态码。

res.header包含了所有子请求的响应头,并且它是一个普通的Lua table。对于多值得响应头,这个值是一个Lua(数组) table,包含了按照顺序出现所有的值。例如:如果子请求响应头包含下面的行:


    Set-Cookie: a = 3
    Set-Cookie: foo = bar
    Set-Cookie: baz = blah

那么res.header["Set-Cookie"]将会等价于表值{"a=3","foo=bar","baz=blah"}

res.body包含了子请求的响应body数据,有可能被截取掉。你一直需要检查res.truncated的boolean标记来检查res.body是否包含截取的数据。这个数据的截取仅仅可能是因为在你子请求中不可恢复的错误造成的,例如远程终端在响应body数据流传输的中间过早的终端连接或者当你子请求在从远端接收响应数据时读取时间超时。

URI查询字符串可以被连接到URI他自身上,例如,


    res = ngx.location.capture('/foo/bar?a=3&b=4')

像一些命名的location例如@foo由于Nginx内核的限制是不允许的。使用普通的location结合internal指令来准备只能内部调用的location。

一个可选的参数表可以作为第二个参数,支持的选项:

  • method
    指定子请求的请求方法,只能接受常量例如 ngx.HTTP_POST

  • body
    指定子请求的请求body (只支持string字符串)

  • args
    指定子请求URI查询字符串 (同时接受字符串值和Lua table)

  • vars
    使用一个包含设置特殊Nginx变量的Lua table到子请求中,通过这个选项的值。这个选项首先在v0.3.1rc31版本中被介绍。

  • copy_all_vars
    指定是否复制当前请求的所有nginx变量到子请求中。在子请求中更改这个nginx变量将不会影响当前(父)请求。这个选项首先在v0.3.1rc31版本中被介绍。

  • share_all_vars

指定子请求是否共享当前(父)请求中的所有Nginx变量。在子请求中更改Nginx变量将会影响当前(父)请求。开启这个选项将会导致难以debug的问题,因为负面影响并且它是不好喝有害的。只有你完全清楚你自己在干什么的时候再开启这个选项。

  • alway_forward_body

发出一个POST子请求时,例如,可以像下面这样:


    res = ngx.location.capture(
          '/foo/bar',
          { method = ngx.HTTP_POST, body = 'hello,world' }
      )

参阅除了POST请求的其他子请求方法。
method选项默认是ngx.HTTP_GET

这个args选项可以指定额外的URI参数,例如,


    ngx.location.capture('/foo?a=1',
        { args = { b = 3,c = ':' } }
    )

这个等价于


    ngx.loation.captur('/foo?a=1&b=3&c=%3a')

这个args选项可以设置普通的查询字符串:

    ngx.location.capture('foo?a=1',{ args = 'b=3&c=%3a' })

这个方法和以前的例子是完全一样的。

这个share_all_vars选项控制是够共享nginx变量,从当前的请求到它的子请求中。

如果这个选项设置的是true,那么当前请求和关联的子请求将会共享相同的Nginx变量范围。因此,在子请求中更改的nginx变量将会影响当前的请求。

应该注意的的是使用这个选项作为变量范围共享将会发生难以预料的影响。一般是推荐argsvars,或者copy_all_vars选项。


    location /other {
      set $dog "$dog world";
      echo "$uri dog:$dog";

    }

    location /lua {
        set $dog 'hello';
        content_by_lua_block {
            res = ngx.location.capture("/other",
              { share_all_vars = true });

            ngx.print(res.body)
            ngx.say(ngx.var.uri,":",ngx.var.dog)
        }
    }

访问location /lua 将会得到


    /other dog:hello world
    /lua: hello world

这个copy_all_vars选线提供一个当前父请求的Nginx变量的副本到子请求中,当发出这些子请求时。通过这样的子请求更改这些变量将不会影响当前父请求或者其他子请求中共享的父请求的变量。


    location /other {
        set $dog "$dog world";
        echo "$uri dog:$dog";

    }

    location /lua {
        set $dog 'hello';
        content_by_lua_block{
            res = ngx.location.capture("/other",{ copy_all_vars = true });
            ngx.print(res.body)
            ngx.say(ngx.var.uri, ": ",ngx.var.dog)
        }
    }

请求 GET/lua将会给出输出


      /other dog:hello world
      /lua: hello

注意如果share_all_varscopy_all_vars被设置为true,那么share_all_vars将会被优先考虑。

除了上面两个设置,可以通过使用vars选项指定在子请求中的变量。这些通过共享或者复制的变量是等价的,并且提供一个更有效的方式来传递特殊的值到子请求中,而不是通过在URL参数中编码和在nginx配置文件中解密它们。


    location /other {
        content_by_lua_block {
          ngx.say("dog = ",ngx.var.dog)
          ngx.say("cat = ",ngx.var.cat)
        }
    }

    location /lua {
        set $dog '';
        set $cat '';
        content_by_lua_block {
            res = ngx.location.capture("/other",
            { vars = { dog = "hello", cat = 32 }});

            ngx.print(res.body)
        }

    }

访问/lua将会产生那样的输出


      dog = hello
      cat = 32


      location /sub {
          content_by_lua_block {
             ngx.ctx.foo = "bar";
          }
      }
      location /lua {
          content_by_lua_block {
              local ctx = {}
              res = ngx.location.capture("/sub",{ ctx = ctx })

              ngx.say(ctx.foo);
              ngx.say(ngx.ctx.foo);
          }
      }

请求GET /lua得到


    bar
    nil

      location /sub {
          content_by_lua_block {
              ngx.ctx.foo = "bar"

          }
      }
      location /lua {
          content_by_lua_block {
              res = ngx.location.capture("/sub",{ ctx = ngx.ctx })
              ngx.say(ngx.ctx.foo);
          }
      }

请求 GET /lua会产生输出

    bar

当没有指定body选项并且always_forward_body选项为false(默认值),这个POSTPUST子请求会继承父请求的body(如果可能的话)。

这里有个硬编码的限制数,限制每个主请求同时并发的子请求数量。在nginx的老版本中,这个限制是50并且在更前的版本中,Nginx 1.1.x之前,这个数量增加到200个并发子请求。当超出这个限制,下面的错误信息将会被添加到error.log文件中:

  [error] 13983#0: *1 subrequests cycle while processing "/uri"

ngx.location.capture_multi

语法: res1,res2,... = ngx.location.capture_multi( {uri,options?},{uri,options?}, ... })

上下文: rewrite_by_lua&$42;, access_by_lua, content_by_lua**

正如[ngx.location.capture],但是支持并行运行多个子请求。

这个方法通过输入table产生几个并行的子请求并且以同样的顺序返回他们的值。例如,


      res1,res2,res3 = ngx.location.capture_multi{
         { "/foo" , {args = "a=3&b=4 "}},
         { "/bar" },
         { "/baz" , {method = ngx.HTTP_POST,body = "hello" }},
      }

      if res1.status = ngx.HTTP_OK then
          ...
      end

      if res2.body == "BLAH" then
          ...
      end

整个方法将不会返回直到所有的子请求终止。
总的延迟是各个子请求中的最长的延迟而不是总和。

Lua table可以用在request和response中,当发起的子请求的数量事前不知道的时候。


    -- construct the request table
    local reqs = {}
    table.insert{reqs, {"/mysql"}}
    table.insert(reqs, {"/postgres"})
    table.insert(reqs, {"/redis"})
    table.insert(reqs, {"/memcached"})

    -- issue all the requests at once and wait until they all return
    local resps = { ngx.location.capture_multi(reqs) }

    -- loop over the responses table
    for i,resp in ipairs(resps) do
        -- process the response table "resp"
    end


  ngx.location.capure =
      function (uri,args)
          return ngx.location.capture_multi({ uri,args })
      end

ngx.status

上下文: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua*

读和写当前请求的响应状态。这应该在发出响应headers之前被调用。


      ngx.status = ngx.HTTP_CREATED
      status = ngx.status

在发送出响应头之后设置ngx.status不会产生影响但是会遗留一个错误信息到你的nginx日志文件中:

attempt to set ngx.status after sending out response headers

ngx.header.header

语法: ngx.header.HEADER = VALUE

语法: value = ngx.header.HEADER

上下文: rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua**

设置,添加,或者清除当前请求的HEADER将要被发送的响应头。

这些标题不区分大小写的匹配。


    -- equivalent to ngx.header["Content-Type"] = 'text/plain'
    ngx.header.content_type = 'text/plain';

    ngx.header["X-My-Header" = 'blah blah']

多值的headers可以通过这种方式发送:


    ngx.header['Set-Cookie'] = { 'a=32;path=/','b=4;path=/'}

将会在响应的headers中产生:


    Set-Cookie: a=32; path=/
    Set-Cookie: b=4;path=/

只接受Lua table (类似Content-Type这些只接受一个值的标准header,只有table中的最后一个值才会起作用)


    ngx.header.content_type = {'a', 'b'}

等价于


    ngx.header.content_type = 'b'

设置这个插槽为nil将会影响它从响应头中被移出:


    ngx.header["X-My-Header"] = nil;

同样也适用于赋值一个空的表:


    ngx.header["X-My-Header"] = {};

读取ngx.header.HEADER将会返回响应头中名为HEADER的值。

在header名称中的下划线(_)也会被连字符(-)替换掉,并且header名称将会大小写无关的匹配。如果响应header没有提供,那么将会返回nil


    location /test {
        set $footer '';

        proxy_pass http://some-backend;

        header_filter_by_lua_block {

            if ngx.header["X-My-Header"] == "blah" then
                ngx.var.footer = "some value"
            end
        }

        echo_after_body $footer;
    }

对于多值得header,所有的header的值将会按照顺序手机并且作为一个Lua table返回。例如,response headers


    Foo: bar
    Foo: baz

将会得到结果


  {"bar", "baz"}

将会被通过ngx.header.Foo读取时返回。

注意ngx.header不是一个普通的Lua table并且同样的,他也不能通过Lua ipairs方法来迭代。

ngx.resp.get_headers

语法: headers = ngx.resp.get_headers(max_headers?,raw?)

上下文: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua, balancer_by_lua**

将返回一个Lua table,持有当前请求的所有的当前的响应headers


    local h = ngx.resp.get_headers()
    for k,v in pairs(h) do
        ...
    end

这个方法和[ngx.req.get_headers]有着同样的特征除了获取的是响应头而不是请求头。

这个接口首先在v0.9.5版本中被介绍。

ngx.req.is_internal

语法 is_internal = ngx.req.is_internal()

上下文 set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua*

返回一个boolean值标记当前的请求是否是一个“内部请求”,例如,一个从nginx服务器端那边生成的请求而不是从客户端那边。

这个接口首先在v0.9.20版本中被介绍。

ngx.req.start_time

语法: secs = ngx.req.start_time()

上下文: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua*

返回一个浮点数表示当前请求创建时候的时间戳(包含毫秒数作为小数部分)


  local request_time = ngx.now() - ngx.req.start_time()

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

ngx.req.http_version

上下文: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua*

以Lua数字的形式返回表示当前request的HTTP版本。

当前可能的值有 2.0,1.0,1.1,和 0.9。对于不识别的值返回nil

这个方法首先在v0.7.17版本中被介绍。

ngx.req.raw_header

语法: str = ngx.req.raw_header(no_request_line?)

上下文: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua*

返回当前Nginx服务器收到的原始的HTTP协议header。

默认情况下,这个请求line和结尾的CR LF终结符也会被包含,例如,


    ngx.print(ngx.req.raw_header())

会得到类似下面的:

      GET /t HTTP/1.1
      Host:localhost
      Connection:close
      Foo:bar

你可以指定可选的no_request_line参数为true来从结果中排出请求line.例如,


      ngx.print(ngx.req.raw_header(true))

将会输出类似下面的:


  Host:localhost
  Connection:close
  Foo:bar

这个方法首先在v0.7.17版本中被介绍。

这个方法在HTTP/2请求中目前不工作。

ngx.req.get_method

语法: method_name = ngx.req.get_method()

上下文: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, balancer_by_lua**

如果当前的请求是一个Nginx子请求,那么将会返回子请求的方法名称。

这个方法首先在v0.7.17版本中被介绍。

ngx.req.set_method

语法: ngx.req.set_method(method_id)

上下文: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua*

如果当前的请求是Nginx子请求,那么子请求的方法将会被覆盖。

这个方法首先在v0.5.6版本中被介绍。

ngx.req.set_uri

语法: ngx.req.set_uri(uri,jump?)

上下文: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua**

通过uri参数来重写当前请求(解析过得)URI,这个uri参数必须是一个Lua字符串兵器不能是0长度,否则一个Lua异常将会被抛出。

另一方面Location跳转将不会被触发,并且只有当前请求的URI会被修改,这个也是默认的行为。这个方法将返回但是当jump参数是false或者缺失的时候没有返回值。

例如,下面是nginx配置的片段


  rewrite ^ /foo last;

可以被Lua编码成这样:


    ngx.req.set_uri("/foo",true)

相似的,Nginx 配置


    rewrite ^ /foo break;

可以被Lua编码成这样


    ngx.req.set_uri("/foo",false)

或者等价于


    ngx.req.set_uri("/foo")

一个包含正则表达式替换的更加复杂的例子如下:


    location /test {

        rewrite_by_lua_block {
            local uri = ngx.re.sub(ngx.var.uri,"^/test/(.*)","/$1","o")
            ngx.req.set_uri(uri)
        }
        proxy_pass http://my_backend;
    }

这个方法等价于


    location /test {
        rewrite ^/test/(.*) /&1 break;
        proxy_pass http://my_backend;
    }

    rewrite ^ /foo?a=3? last;

可以被编码成为:


    ngx.req.set_uri_args("a=3")
    ngx.req.set_uri("/foo",true)

或者


    ngx.req.set_uri_args({ a = 3})
    ngx.req.set_uri("/foo",true)

这个接口首先在v0.3.1rc14版本中被介绍。

ngx.req.set_uri_args

语法: ngx.req.set_uri_args(args)

上下文: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua**

通过args参数来重写当前请求中的URI请求参数。这个args参数既可以是Lua string,例如


    ngx.req.set_uri_args("a=3&b=hello%20world")

或者一个包含查询参数的key-value对的Lua table,例如


    ngx.req.set_uri_args({ a = 3, b = "hello world" })

当是后面的情况时,这个方法将参数的中的key和value将不需要URI转移规则。

多值参数也可以通过下面提供:


    ngx.req.set_uri_args({ a = 3,b = {5, 6}})

这个将会转成查询字符串例如 a=3&b=5&b=6

这个接口首先在v0.3.1rc13版本中被介绍。

ngx.req.get_uri_args

语法: args = ngx.req.get_uri_args(max_args?)

上下文: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua, balancer_by_lua**

返回一个持有所有当前请求URL查询参数的Lua表。


    location = /test {
        content_by_lua_block {
            local args = ngx.req.get_uri_args()
            for key,val in pairs(args) do
              if type(val) == 'table' then
                  ngx.say(key,":",table.concat(val,", "))
              else
                  ngx.say(key,": ",val)
              end
             end
        }
    }

然后 GET /test?foo=bar&bar=baz&bar=blah会产生响应体


      foo:bar
      bar:baz,blah

多次出现的参数key会得到一个table,持有所有的值,这些值按顺序排列,共用同一个key。

key和value不按照URI转义规则转义。在上面的设置中,GET /test?a%20b=1%61+2会产生:


    a b: 1a 2

参数中没有=<value>部分的被当做是一个boolean参数。GET /test?foo&bar 会产生:


    foo:true
    bar:true

也就是说,他们会使用Lua boolean值ture。然而,他们和参数中种使用空字符串的不同。GET /test?foo=&bar=将会得到这样的结果


  foo:
  bar:

key为空的参数将会被丢弃。例如GET /test?=hello&=world将会导致一个空的输出。

支持在运行过程中通过nginx变量$args(或者Lua里面的 ngx.var.args)来更新查询参数。


    ngx.var.args = "a=3&b=42"
    local args = ngx.req.get_uri_args()

这里的args table将一直是这个样子


 {a = 3, b = 42}

而不管实际请求的字符串是什么。

注意,默认最大解析100个请求参数(包括这些有着同样名称的)并且额外的请求参数会被默默的丢弃,以防止拒绝服务式攻击。

然而,这个max_args函数参数可以用来覆盖这个极限:


 local args = ngx.req.get_uri_args(10)

这个参数可以设置为0,来限制和处理所有的请求参数:


  local args = ngx.req.get_uri_args(0)

强烈不建议覆盖掉max_args参数。

ngx.req.get_post_args

语法: args, err = ngx.req.get_post_args(max_args?)

上下文: rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua**


 location = /test {
     content_by_lua_block {
         ngx.req.read_body()
         local args, err = ngx.req.get_post_args()
         if not args then
             ngx.say("failed to get post args: ", err)
             return
         end
         for key, val in pairs(args) do
             if type(val) == "table" then
                 ngx.say(key, ": ", table.concat(val, ", "))
             else
                 ngx.say(key, ": ", val)
             end
         end
     }
 }

然后


 # Post request with the body 'foo=bar&bar=baz&bar=blah'
 $ curl --data 'foo=bar&bar=baz&bar=blah' localhost/test

会产生如下的响应body


 foo: bar
 bar: baz, blah

多次出现的参数key会得到一个table,持有所有的值,这些值按顺序排列,共用同一个key。

key和value不按照URI转义规则转义。在上面的设置中,


 # POST request with body 'a%20b=1%61+2'
 $ curl -d 'a%20b=1%61+2' localhost/test

会产生


 a b: 1a 2

参数中没有=<value>部分的被当做是一个boolean参数。GET /test?foo&bar 会产生:


    foo:true
    bar:true

也就是说,他们会使用Lua boolean值ture。然而,他们和参数中种使用空字符串的不同。POST /test使用请求 body foo=&bar= 将会返回如下的信息。


 foo:
 bar:

key为空的参数将会被丢弃。例如POST /test 使用body =hello&=world 将会导致一个空的输出。

注意,默认最大解析100个请求参数(包括这些有着同样名称的)并且额外的请求参数会被默默的丢弃,以防止拒绝服务式攻击。

然而,这个max_args函数参数可以用来覆盖这个极限:


 local args = ngx.req.get_post_args(10)

这个参数可以设置为0,来限制和处理所有的请求参数:


 local args = ngx.req.get_post_args(0)

强烈不建议覆盖掉max_args参数。

ngx.req.get_headers

语法: headers = ngx.req.get_headers(max_headers?, raw?)

context: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua*

返回一个包含当前所有请求headers的Lua table。


 local h = ngx.req.get_headers()
 for k, v in pairs(h) do
     ...
 end

要读取个别的header:


 ngx.say("Host: ", ngx.req.get_headers()["Host"])

对于多个实体的请求header例如:


 Foo: foo
 Foo: bar
 Foo: baz

ngx.req.get_headers()["Foo"]的值将会是一个Lua(array) table,例如:


 {"foo", "bar", "baz"}

注意,默认最大解析100个请求参数(包括这些有着同样名称的)并且额外的请求参数会被默默的丢弃,以防止拒绝服务式攻击。

然而,这个max_headers函数参数可以用来覆盖这个极限:


 local headers = ngx.req.get_headers(10)

这个参数可以设置为0,来限制和处理所有的请求参数:


 local headers = ngx.req.get_headers(0)

强烈不建议覆盖掉max_args参数。

0.6.9版本开始,所有在Lua table中返回的header名称被默认转换成纯小写形式的,除了raw参数被设置为true(默认是false)。

并且,默认情况下,一个__index原方法被加入到结果Lua table中并且会是说是有的key规范为纯小写形式,将所有连字符下划线转换为下划线形式,以防止查找不到。例如,如果给出了一个 My-Foo-Header的请求header,那么下面的调用都能成功的获取这个header的值:


 ngx.say(headers.my_foo_header)
 ngx.say(headers["My-Foo-Header"])
 ngx.say(headers["my-foo-header"])

raw参数被设置为true后,这个_index元方法将不会被添加。

ngx.req.set_header

语法: ngx.req.set_header(header_name, header_value)

上下文: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua**

将当前请求的header名称为 header_name转换为header_value,覆盖任何现有的。

这里有个设置Content-Type header的例子:


 ngx.req.set_header("Content-Type", "text/css")

这个header_value可以使用列表数据,例如。


 ngx.req.set_header("Foo", {"a", "abc"})

将会产生两个新的request headers:


 Foo: a
 Foo: abc

并且如果存在老的Foo headers的话将会被覆盖掉。

当这个 header_value 参数是nil,这个请求header将会被移除。所以


 ngx.req.set_header("X-Foo", nil)

等价于


 ngx.req.clear_header("X-Foo")

ngx.req.clear_header

语法: ngx.req.clear_header(header_name)

上下文: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua**

清除当前请求中名称为header_name的请求header。当前请求中存在的子请求将不会受到影响,但是随后产生的子请求默认会继承这个修改。

ngx.req.read_body

语法: ngx.req.read_body()

上下文: rewrite_by_lua, access_by_lua, content_by_lua*

同步的读取客户端的请求body而不会阻塞Nginx事件循环。


 ngx.req.read_body()
 local args = ngx.req.get_post_args()

在发生错误的情况下,如在读取数据时发生连接错误,这个方法将会抛出一个Lua异常 或者 立即终止当前的请求返回一个500错误码。

这个方法首先在 v0.3.1rc17版本中被介绍。

ngx.req.discard_body

语法: ngx.req.discard_body()

上下文: rewrite_by_lua, access_by_lua, content_by_lua*

明确地丢弃请求body,例如,在连接中读取数据并立即将其丢弃(不使用请求主体)。

这个方法是异步调用并且会立即返回。

如果这个请求body已经被读取了,这个方法什么也不做并且会立即返回。

这个方法首先在v0.3.1rc17版本中被介绍。

另请参阅 [ngx.req.read_body](#ngxreqread_body。

ngx.req.get_body_data

语法: data = ngx.req.get_body_data()

上下文: rewrite_by_lua, access_by_lua, content_by_lua, log_by_lua**

这个方法将会返回nil如果

  1. 请求body没有没读取,
  2. 请求body已经被读取到磁盘临时文件里面,
  3. 或者请求body只有0长度。

注意调用这个方法而不是使用ngx.var.request_body或者ngx.var.echo_request_body是更有效率的,因为它可以保存一个动态内存分配和一个数据副本。

这个方法首先在v0.3.1rc17版本中被介绍。

ngx.req.get_body_file

语法: file_name = ngx.req.get_body_file()

上下文: rewrite_by_lua, access_by_lua, content_by_lua*

重新获取已经在文件内部的请求body数据的文件名称。如果请求body没有被读取或者已经被读取到内存中了,将返回nil值。

返回的文件是只读的并且通常被Nginx的内存池清除掉。它不应该被认为的修改,重命名或者在Lua代码里面移除。

这个方法首先在v0.3.1rc17版本中被介绍。

ngx.req.set_body_data

语法: ngx.req.set_body_data(data)

上下文: rewrite_by_lua, access_by_lua, content_by_lua*

使用data参数指定的内存数据来设置当前请求中的请求body。

如果当前请求的请求body没有被读取,那么将会被适当的丢弃。如果当前请求的请求body已经被读取到内存或者缓存到磁盘文件中,那么老的请求body的内存将会被释放或者磁盘文件将会被立即清除,分别的。

这个方法首先在v0.3.1rc17版本中被介绍。

ngx.req.set_body_file

语法: ngx.req.set_body_file(file_name, auto_clean?)

上下文: rewrite_by_lua, access_by_lua, content_by_lua*

通过使用file_name参数中指定的在文件中的数据来设置当前请求的请求body。

请保证通过file_name参数指定的文件存在并且是被Nginx工作进程可读取的,用过设置恰当的权限来避免Lua异常错误。

如果当前请求的请求body没有被读取,那么将会被适当的丢弃如果当前请求的请求body已经被读取到内存或者缓存到磁盘文件,那么老的请求body内存将会被释放或者磁盘文件将会被立即清除,分别的。

这个方法首先在v0.3.1rc18版本中被介绍。

ngx.req.init_body

语法: ngx.req.init_body(buffer_size?)

上下文: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua**

当对于请求body,数据不能被内存缓冲区来保存时,这个数据将会被刷新到一个临时文件中,就如同在Nginx内核中的标准的请求body读取器一样。

这个方法使用经常如下:


 ngx.req.init_body(128 * 1024)  -- buffer is 128KB
 for chunk in next_data_chunk() do
     ngx.req.append_body(chunk) -- each chunk can be 4KB
 end
 ngx.req.finish_body()

这个方法首先在v0.5.11版本中被介绍。

ngx.req.append_body

语法: ngx.req.append_body(data_chunk)

上下文: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua**

当对于请求body,数据不能被内存缓冲区来保存时,这个数据将会被刷新到一个临时文件中,就如同在Nginx内核中的标准的请求body读取器一样。

这个方法首先在v0.5.11版本中被介绍。

ngx.req.finish_body

语法: ngx.req.finish_body()

上下文: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua**

这个方法首先在v0.5.11版本中被介绍。

Top