摘自:http://www.daileinote.com/computer/openresty/08
ngx.req.is_internal 1 syntax: is_internal = ngx.req.is_internal()
判断是否为内部请求。
ngx.get_phase 1 syntax: str = ngx.get_phase()
获取当前阶段名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 init init_worker ssl_cert ssl_session_fetch ssl_session_store set rewrite balancer access content header_filter body_filter log timer
ngx.req.start_time 1 syntax: secs = ngx.req.start_time()
返回请求创建的时间戳,格式为 1533118835.492。
ngx.req.http_version 1 syntax: num = ngx.req.http_version()
返回 http 协议版本比如 2.0、1.0、1.1、0.9,识别不了返回 nil 。
1 syntax: str = ngx.req.raw_header(no_request_line?)
默认返回请求行 + 请求头,传入 true 代表去掉请求行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 location /test { default_type text/html; content_by_lua_block { ngx.print(ngx.req.raw_header()) ngx.print(ngx.req.raw_header(true )) } } [root@192 ~] GET /test HTTP/1.1 User-Agent: curl/7.29.0 Host: localhost Accept: */* User-Agent: curl/7.29.0 Host: localhost Accept: */*
ngx.req.get_method 1 syntax: method_name = ngx.req.get_method()
获取请求方法比如 "GET" "POST" 等。
ngx.req.set_uri 1 syntax: ngx.req.set_uri(uri, jump?)
重写url,jump设置为 true 会触发 location 重新匹配,默认为 false。
等同于
1 ngx.req.set_uri("/foo" , true )
等同于
1 2 ngx.req.set_uri("/foo" , false ) ngx.req.set_uri("/foo" )
如果 jump 设置为 true 执行 location 重新匹配,只能在 rewrite_by_lu* 里调用,在其他地方将会出错。
1 2 3 4 5 6 7 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; }
等同于
1 2 3 4 location /test { rewrite ^/test/(.*) /$1 break ; proxy_pass http://my_backend; }
ngx.req.set_method 1 syntax: ngx.req.set_method(method_id)
利用常量id设置请求头比如 ngx.HTTP_POST,如果当前是子请求,那么子请求方法会被覆盖。
ngx.req.set_uri_args 1 syntax: ngx.req.set_uri_args(args)
设置重写的uri参数,args可以是字符串或者是表格。
1 2 3 4 5 ngx.req.set_uri_args("a=3&b=hello+world" ) ngx.req.set_uri_args({ a = 3 , b = "hello world" }) ngx.req.set_uri_args({ a = 3 , b = {5 , 6 } })
下面等同
1 rewrite ^ /foo?a=3? last;
等同于
1 2 3 4 5 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 )
ngx.req.get_uri_args 1 syntax: args, err = ngx.req.get_uri_args(max_args?)
获取请求参数到表格,默认最大参数为 100个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 location = /test { content_by_lua_block { local args, err = ngx.req.get_uri_args(100) if err == "truncated" then -- 超过了最大参数个数会到此 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 } } [root@192 ~] no_equal: true name: freecls, 222 has_equal: age: 22
支持动态修改 $args 变量。
1 2 3 4 ngx.var.args = "a=3&b=42" local args, err = ngx.req.get_uri_args()
max_args 设置为 0 代表不限制参数个数,但是极度不推荐。
1 local args, err = ngx.req.get_uri_args(0 )
ngx.req.get_post_args 1 syntax: args, err = ngx.req.get_post_args(max_args?)
解析请求体数据为表格(mime 类型必须为 application/x-www-form-urlencoded)。注意:必须先读取请求体比如 ngx.req.read_body() 或者 lua_need_request_body on。其他的同上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 location = /test { content_by_lua_block { ngx.req.read_body() local args, err = ngx.req.get_post_args() if err == "truncated" then -- 超过了最大参数个数会到此 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 } } [root@192 ~] err:nil no_equal: true name: freecls, 222 has_equal: age: 22
1 syntax: headers, err = ngx.req.get_headers(max_headers?, raw?)
获取请求头到表格,如果只是过去单个请求头,最好使用 nginx 内部变量。nginx 内部变量的请求头名都是经过转化的,连字符转为下划线并且全部转化为小写,多个同名请求头只取第一个。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 location = /test { content_by_lua_block { local h, err = ngx.req.get_headers() if err == "truncated" then -- 超过最大请求头限制 end for key, val in pairs(h) do if type (val) == "table" then ngx.say(key, ": " , table.concat(val, ", " )) else ngx.say(key, ": " , val) end end --通过 nginx 内部变量获取 -- 注意连字符 - 将会被转化为 _ ngx.say(ngx.var["http_head_cus" ]) } } [root@192 ~] host: localhost user-agent: curl/7.29.0 accept: */* name: 1, 2 head-cus: freecls, cus2 freecls
第二个参数默认为 false,__index 元方法将会加入到结果表格该方法将请求头名称将会转化为小写,并且将会把下划线 _ 转化为连字符 - 。
下面几个都能获取到请求头。
1 2 3 ngx.say(headers.head_cus) ngx.say(headers["Head-Cus" ]) ngx.say(headers["head-cus" ])
如果第二个参数设为 true,那么就不会转化任何请求头,那么下面两个请求头要分别获取。
1 2 3 ngx.say(headers["head-cus" ]) ngx.say(headers["Head-Cus" ])
1 syntax: ngx.req.set_header(header_name, header_value)
设置或覆盖请求头,主要用于子请求,因为子请求会继承当前请求头。
1 2 3 4 5 6 7 8 ngx.req.set_header("Content-Type" , "text/css" ) ngx.req.set_header("Foo" , {"a" , "abc" }) ngx.req.set_header("X-Foo" , nil ) ngx.req.clear_header("X-Foo" )
移除请求头
1 syntax: ngx.header.HEADER = VALUE
获取、新增、修改、清除响应头,下划线 _ 将会被替换成连字符 - 。可以通过 lua_transform_underscores_in_response_headers 配置指令来关闭。而且是大小写不敏感的。获取时不存在则返回 nil。
1 2 3 4 ngx.header["Content-Type" ] = 'text/plain' ngx.header.content_type = 'text/plain' ; ngx.header["X-My-Header" ] = 'blah blah' ;
支持多个值
1 2 3 4 ngx.header['Set-Cookie' ] = {'a=32; path=/' , 'b=4; path=/' }
多个值但是该响应头只支持一个值,那么取最后那个。
1 2 3 ngx.header.content_type = {'a' , 'b' } ngx.header.content_type = 'b'
移除请求头
1 2 3 ngx.header["X-My-Header" ] = nil ; ngx.header["X-My-Header" ] = {};
一般放在 header_filter_by_lua* 阶段来处理
1 2 3 4 5 6 7 8 9 10 11 12 13 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 ; }
ngx.header 不是常规的表格,所以不能遍历。
1 syntax: headers, err = ngx.resp.get_headers(max_headers?, raw?)
返回所有响应头存放在表格里,用法请参照 ngx.req.get_headers。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 location = /test { content_by_lua_block { local h, err = ngx.resp.get_headers() if err == "truncated" then -- 超过最大请求头限制 end for key, val in pairs(h) do if type (val) == "table" then ngx.say(key, ": " , table.concat(val, ", " )) else ngx.say(key, ": " , val) end end } } [root@192 ~] connection: keep-alive content-type: application/octet-stream
ngx.req.read_body 1 syntax: ngx.req.read_body()
读取请求体并保存,如果超过了 client_body_buffer_size 指定的大小将会存入临时文件。所有需要用到请求体的 API 都必须先读取请求体。或者设置 lua_need_request_body on。
ngx.req.discard_body 1 syntax: ngx.req.discard_body()
显性的接收请求体并丢弃,立马返回。一般用于客户端带上了请求体,但是服务端用不到。
ngx.req.get_body_data 1 syntax: data = ngx.req.get_body_data()
以字符串形式返回读取到内存里的请求体数据。如下情形之一的会返回 nil:
1.没有读取请求体比如没调用 ngx.req.read_body() 2.请求体存入了临时文件 3.请求体大小为0
用它来获取请求体比用变量 $request_body 快,因为少一次内存分配。
ngx.req.get_body_file 1 syntax: file_name = ngx.req.get_body_file()
返回存取请求体的临时文件名,没有读取请求体或者请求体存在内存里返回 nil。
返回的文件名只读,nginx 会帮助我们删除。
ngx.req.set_body_data 1 syntax: ngx.req.set_body_data(data)
设置请求体,也要先读取请求体。
ngx.req.set_body_file 1 syntax: ngx.req.set_body_file(file_name, auto_clean?)
设置读取请求体的文件名,也要先读取请求体。auto_clean 默认为 false,请求结束后不会移除文件。
如果设置 auto_clean 为true,那么当请求结束或者在当前请求调用 ngx.req.set_body_data 将会移除文件,必须保证改文件存在并且 nginx 拥有适当的权限操作该文件。
ngx.req.init_body 1 syntax: ngx.req.init_body(buffer_size?)
创建新的块来存储请求体,默认为 client_body_buffer_size 。超过该大小会存入临时文件,跟正常请求处理逻辑一样。
一般在 rewrite_by_lua* 或者 access_by_lua* 阶段配合 ngx.req.append_body,ngx.req.finish_body,ngx.req.socket 实现高效输入过滤,同样可以配合 upstream 模块比如 ngx_http_proxy_module 和 ngx_http_fastcgi_module。
ngx.req.append_body 1 syntax: ngx.req.append_body(data_chunk)
附加新的块到 ngx.req.init_body 创建的缓冲区。
ngx.req.finish_body 1 syntax: ngx.req.finish_body()
标记结束。
1 2 3 4 5 ngx.req.init_body(128 * 1024) -- buffer is 128KB for chunk in next_data_chunk() do ngx.req.append_body(chunk) -- 一次读取 4KB end ngx.req.finish_body()
ngx.req.socket 1 syntax: tcpsock, err = ngx.req.socket(raw)
返回只读的 cosocket 对象,可以通过 receive 和 receiveuntil 来接收数据,一般是用来以流的形式接收大量的请求体。注意不要开启 lua_need_request_body。
如果指定了 raw 参数为true,那么就是原始的 tcp 连接,可以使用 receive 和 receiveuntil 和 send 收发数据,但是之前不能有准备发送的数据比如之前调用了 ngx.say()、ngx.print、ngx.send_headers等,如果有,那么要先调用 ngx.flush(true) 发送出去。
详细用法请参照 openresty - lua API(7) ,这篇文章讲的是与上游服务器的tcp或者是udp连接,也就是跟当前 http 请求连接是无关的。
而 ngx.req.socket 创建的是用来处理当前 http 连接的,可以接收当前 http 的请求体,也可以发送响应给浏览器客户端。
1 syntax: ok, err = ngx.send_headers()
主动发送响应头,成功返回 1,失败返回 nil 加错误信息。一般无需调用,ngx.say、ngx.print 或者 content_by_lua* 正常结束都会自动发送响应头。
1 syntax: value = ngx.headers_sent
返回 true 代表响应头已经发送。
ngx.is_subrequest 1 syntax: value = ngx.is_subrequest
返回true,如果是子请求。
ngx.on_abort 1 syntax: ok, err = ngx.on_abort(callback)
注册回调函数,当客户端非正常关闭连接时调用,必须设置 lua_check_client_abort on。
1 2 3 4 5 6 7 8 9 10 11 12 local function my_cleanup () ngx.exit (499 ) end local ok, err = ngx.on_abort(my_cleanup) if not ok then ngx.log (ngx.ERR, "failed to register the on_abort callback: " , err) ngx.exit (500 ) end
时间相关 ngx.today 1 syntax: str = ngx.today()
从 nginx 缓存里获取 yyyy-mm-dd 格式的时间,没有额外的系统调用。
ngx.time 1 syntax: secs = ngx.time()
从 nginx 缓存里获取时间戳。
ngx.now 1 syntax: secs = ngx.now()
从 nginx 缓存里获取时间戳,小数位为毫秒,格式为 1533134658.555。
ngx.update_time 1 syntax: ngx.update_time()
要 nginx 更新缓存时间,会造成系统调用。
ngx.localtime 1 syntax: str = ngx.localtime()
从 nginx 缓存里获取本地时间格式为 yyyy-mm-dd hh:mm:ss。
ngx.utctime 1 syntax: str = ngx.utctime()
从 nginx 缓存里获取 UTC 时间格式为 yyyy-mm-dd hh:mm:ss。
ngx.cookie_time 1 syntax: str = ngx.cookie_time(sec)
转化时间戳为 cookie 的时间格式。
ngx.http_time 1 syntax: str = ngx.http_time(sec)
转化时间戳为 http头使用的时间格式,比如 Last-Modified。
ngx.parse_http_time 1 syntax: sec = ngx.parse_http_time(str)
转化 http格式时间为时间戳。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 location = /test { content_by_lua_block { ngx.say(ngx.today()) ngx.say(ngx.time()) ngx.say(ngx.now()) ngx.say(ngx.localtime()) ngx.say(ngx.utctime()) ngx.say(ngx.cookie_time(ngx.time())) ngx.say(ngx.http_time(ngx.time())) ngx.say(ngx.parse_http_time("Thu, 18 Nov 2010 11:27:35 GMT" )) } } [root@192 ~] 2018-08-01 1533134658 1533134658.555 2018-08-01 22:44:18 2018-08-01 14:44:18 Wed, 01-Aug-18 14:44:18 GMT Wed, 01 Aug 2018 14:44:18 GMT 1290079655