openresty - lua API(1) - 基础、常量

2018-08-01 12:11:18

下面介绍的 Lua API 可以在 *_by_lua_block 和 *_by_lua_file 指定的 Lua 代码里调用,这些 API 很好的桥接了 nginx 和 Lua。

ngx.arg

syntax: val = ngx.arg[index]
context: body_filter_by_lua*

在响应体过滤时候 ngx.arg[1] 代表响应体内容,ngx.arg[2] 代表该块的标志位。参照 配置指令 body_filter_by_lua_block。

ngx.var.VARIABLE

这个指令可以获取 nginx 的变量,注意,在一次请求里 nginx 变量读取的时候会分配一次内存,在请求结束的时候会释放,所以如果需要反复使用该变量的值,可以保存为本地 lua 变量。

未定义的变量返回 nil,定义了未初始化的返回空字符串。

把变量设置为 nil,会清除该变量。

ngx.var.args = nil

例子

location /f {
    set $a 1;
    set $b 2;
    content_by_lua_file test.lua;
}
--test.lua
local t1 = ngx.var.a
local t3 = ngx.var.uri

ngx.say(t1," ", t3)
[root@192 ~]# curl localhost/f
1  /f

print

输出到 error.log 文件,日志级别为 ngx.NOTICE。等同于

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

nil、true、false、ngx.null(null) 都会以字符串形式输出到日志。默认最大长度为 2048,除非修改 src/core/ngx_log.h 的 NGX_MAX_ERROR_STR 宏。

ngx.log

同上,记录日志,可以指定日志级别。

error_log  logs/error.log  notice;
location /f {
    set $a 1;
    set $b 2;
    content_by_lua_block {
	ngx.say("http://www.freecls.com")
	ngx.log(ngx.NOTICE,ngx.null," ", nil)
    }
    #body_filter_by_lua_block {print(ngx.arg[1])}
}
[root@192 ~]# curl localhost/f
http://www.freecls.com
[root@192 openresty]# tail -f logs/error.log 

2018/08/01 15:34:39 [notice] 96234#0: *46 [lua] content_by_lua(nginx.conf:49):3: null nil \
, client: 127.0.0.1, server: localhost, request: "GET /f HTTP/1.1", host: "localhost"

ngx.ctx

该表格可以存储每个请求的上下文数据,在同一个请求里共享,生命周期伴随当前请求。

不到非使用不可,建议不要用,因为查询 ngx.ctx 需要调用元方法,比较耗时。

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)
     }
 }
79

但是子请求会有其自己的上下文。

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)
     }
 }
 main pre: 73
 sub pre: nil
 sub post: 32
 main post: 73

内部重定向将会清空 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")
     }
 }
nil

如果想要在自己的模块函数里操作 ngx.ctx,可以当做参数传递,因为表格传递的是引用,请求结束后会自动销毁。

 -- mymodule.lua
 local _M = {}

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

 return _M

ngx.print

输出响应体,如果响应头没发送,那么会先发送响应头。成功返回1 失败返回 nil 加错误信息。可以输出 nil、true、false 为响应的字符串,ngx.null 会输出成 null。如果传入的是表格,会一个接一个的输出。

ngx.print() 是异步调用,会立马返回,不会等到数据全部存入发送缓冲区。想同步操作,可以在后面跟上 ngx.flush(true)。

但是有一点需要注意,ngx.print 会调用所有的响应体过滤链,同步模式可能会比较耗时。

ngx.say

同上,只是会在最后附上换行符。

location /f {
    set $a 1;
    set $b 2;
    content_by_lua_block {
    	ngx.print(1)
	ngx.print(2)
	ngx.say(3)
	ngx.say(4)
    }
    body_filter_by_lua_block {print(ngx.arg[1])} #记录日志,看看调用了几次
}

由于 ngx.print() 或者 ngx.say() 会一个接一个的输出,所以上面的 body_filter_by_lua* 响应体过滤至少会调用 4 次。

ngx.flush

ngx.flush(bool)

刷新响应体内容到系统的发送缓冲区,接收一个bool参数,默认为 false,代表异步,立马返回。如果设为 true,那么为同步模式,要等到所有的内容经过过滤链后才返回,或者是超时时间到了也返回。

ngx.status

设置响应状态码,必须在响应头发送之前。

ngx.exit

ngx.exit(status)

当 status >= 200,将会终止当前请求并返回状态码。当 status == 0,只会终止当前阶段,会继续执行下一阶段。status 一般由常量指定,也可以直接用数字代替。

最好配合 return 使用来强调该请求已经结束。

location /f {
    content_by_lua_block {
	ngx.status = ngx.HTTP_GONE
 	ngx.say("This is our own content")
 	return ngx.exit(ngx.HTTP_OK)
    }
}
[root@192 ~]# curl localhost/f -v
...
> 
< HTTP/1.1 410 Gone
< Server: openresty/1.13.6.2
< Date: Wed, 01 Aug 2018 07:50:12 GMT
< Content-Type: application/octet-stream
< Transfer-Encoding: chunked
< Connection: keep-alive
< 
This is our own content

ngx.eof

syntax: ok, err = ngx.eof()

主动标记响应体的结束,相当于 nginx 里面发送一个有 last_buf 标记的链。如果不是 keepalive,那么会主动让http客户端关闭连接。利用这个特性,我们可以在发送完响应体后让客户端关闭连接,然后我们可以在后台继续处理额外的事情而不必让客户端干等着。

location /f {
    keepalive_timeout 0;  //关闭keepalive
    content_by_lua_block {
        ngx.say("got the task!")
        ngx.eof()  -- 客户端会主动关闭连接
         
        #此时连接已经关闭,可以做一些额外的工作。
    }
}

但是如果是创建子请求到上游服务器,必须要配置 upstream 模块忽略客户端连接的关闭,因为在默认的情况下,如果客户端连接关闭,那么 ngx_http_proxy_module 模块会关闭子请求和主请求。所以必须要有如下配置

proxy_ignore_client_abort on;

当然后台工作更好的方式是利用 ngx.timer.at 定时器。

ngx.sleep

syntax: ngx.sleep(seconds)

非阻塞睡眠,精度到毫秒

--睡眠1毫秒
ngx.sleep(0.001)


核心常量

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

ngx.exit 接受 ngx.OK、ngx.ERROR、ngx.DECLINED。

ngx.null 常量在 Lua 表格中代表 nil。

HTTP 请求方法常量

  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_PROPPATCH (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)

状态码常量

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_PERMANENT_REDIRECT (308)
   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_UPGRADE_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_METHOD_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.3.1rc38 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)

日志级别常量

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


备注

1.测试环境centos7 64位,openresty 版本为 1.13.6.2。
2..原文地址http://www.freecls.com/a/2712/ef


©著作权归作者所有
收藏
推荐阅读
简介
天降大任于斯人也,必先苦其心志。