openresty ngx.ctx请求上下文
官网:https://github.com/openresty/lua-nginx-module#ngxctx
请求上下文
ngx.ctx:请求上下文
# 语法格式
ngx.ctx.name = value
ngx.ctx = { foo = 32, bar = 54 }
环境: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*, exit_worker_by_lua*
This table can be used to store per-request Lua context data and has a
life time identical to the current request (as with the Nginx variables)
* ngx.ctx是个表结构,用来存储每个请求的上下文
* 请求结束后,table存储的数据清空
ngx_lua 执行顺序
正常请求
ngx.ctx.foo entry persists across the rewrite, access, and content
phases of a request
* ngx.ctx在rewrite、access、content等阶段都会存储请求的上下文
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
子请求
Every request, including subrequests, has its own copy of the table
* 每个请求,包括子请求,都会有自己的请求上下文,互不影响
modification of the ngx.ctx.blah entry in the subrequest does not
affect the one in the parent request. This is because they have
two separate versions of ngx.ctx.blah
* 修改子请求的值,不会影响主请求的上下文
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
重定向
Internal redirects (triggered by nginx configuration directives
like error_page, try_files, index and etc) will destroy the
original request ngx.ctx data (if any) and the new request will
have an empty ngx.ctx table
* 内部重定向会破坏请求的上下文,
* 重定向后,生成新的请求,上下文为空
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
ssl 安全连接
Because HTTP request is created after SSL handshake, the ngx.ctx created
in ssl_certificate_by_lua*, ssl_session_store_by_lua*,
ssl_session_fetch_by_lua* and ssl_client_hello_by_lua* is not available
in the following phases like rewrite_by_lua*
* http请求是在ssl连接之后创建,在ssl_certificate_by_lua*、ssl_session_store_by_lua*、
* ssl_session_fetch_by_lua* 、ssl_client_hello_by_lua*中
* 设置的ngx.ctx不会被后续的执行阶段读取
生成新的请求上下文
Overriding ngx.ctx with a new Lua table is also supported
* 可是使用心得lua table覆盖原来的请求上下文
ngx.ctx = { foo = 32, bar = 54 }
使用注意
When being used in the context of init_worker_by_lua*, this table just
has the same lifetime of the current Lua handler.
* ngx.ctx在init_worker_by_lua*创建时,生命周期和当前的lua handler相同
The ngx.ctx lookup requires relatively expensive metamethod calls and
it is much slower than explicitly passing per-request data along by your
own function arguments. So do not abuse this API for saving your own
function arguments because it usually has quite some performance impact
* 和函数传递数据相比,ngx.ctx数据传递很耗性能
不要用local修饰ngx.ctx
Because of the metamethod magic, never "local" the ngx.ctx table
outside your Lua function scope on the Lua module level due to
worker-level data sharing
* 由于worker级别的数据共享,不要用local修饰ngx.ctx
-- 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
使用示例
default.conf
server {
listen 80;
server_name localhost;
location / {
root /usr/local/openresty/nginx/html;
index index.html index.htm;
}
location /test {
rewrite_by_lua_block {
ngx.ctx.name = '瓜田李下';
ngx.ctx.age = 20;
}
access_by_lua_block {
ngx.ctx.age = ngx.ctx.age + 1;
}
content_by_lua_block {
ngx.say("content name ==> ", ngx.ctx.name);
ngx.say("content age ==> ", ngx.ctx.age);
ngx.ctx.age = ngx.ctx.age + 1;
ngx.say("content age ==> ", ngx.ctx.age);
}
header_filter_by_lua_block {
ngx.header.age = ngx.ctx.age
}
}
location /main {
rewrite_by_lua_block {
ngx.ctx.name = '瓜田李下';
ngx.ctx.age = 20;
}
content_by_lua_block {
ngx.say("主请求 name ==> ", ngx.ctx.name);
local res = ngx.location.capture("/sub");
ngx.print(res.body);
}
header_filter_by_lua_block {
ngx.header.age ="主请求 " .. ngx.ctx.age
}
}
location /sub {
rewrite_by_lua_block {
ngx.ctx.name = '海贼王';
ngx.ctx.age = 21;
}
content_by_lua_block {
ngx.say("子请求 name ==> ", ngx.ctx.name);
}
header_filter_by_lua_block {
ngx.header.age = ngx.ctx.age
}
}
location /redirect {
rewrite_by_lua_block {
ngx.ctx.name = '瓜田李下';
ngx.ctx.age = 20;
}
content_by_lua_block {
ngx.exec("/new");
}
header_filter_by_lua_block {
ngx.header.redirect_age ="redirect " .. ngx.ctx.age
}
}
location /new {
rewrite_by_lua_block {
ngx.ctx.name = '海贼王';
ngx.ctx.age = 21;
}
content_by_lua_block {
ngx.say("new name ==> ", ngx.ctx.name);
}
header_filter_by_lua_block {
ngx.header.new_age = "new " .. ngx.ctx.age
}
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/openresty/nginx/html;
}
}
创建容器
docker run -it -d --net fixed --ip 172.18.0.100 -p 4000:80 \
-v /Users/huli/lua/openresty/cache/default.conf:/etc/nginx/conf.d/default.conf \
--name open5 lihu12344/openresty
使用测试
# 正常请求执行流程
huli@hudeMacBook-Pro cache % curl -i localhost:4000/test
HTTP/1.1 200 OK
Server: openresty/1.21.4.1
Date: Thu, 21 Jul 2022 05:03:01 GMT
Content-Type: application/octet-stream
Transfer-Encoding: chunked
Connection: keep-alive
age: 21 --content修改的age不会对header_filter_by_lua_block产生影响
content name ==> 瓜田李下
content age ==> 21
content age ==> 22
# 子请求执行:子请求创建新的请求上下文
huli@hudeMacBook-Pro cache % curl -i localhost:4000/main
HTTP/1.1 200 OK
Server: openresty/1.21.4.1
Date: Thu, 21 Jul 2022 05:03:05 GMT
Content-Type: application/octet-stream
Transfer-Encoding: chunked
Connection: keep-alive
age: 主请求 20
主请求 name ==> 瓜田李下
子请求 name ==> 海贼王
# 重定向请求:子请求创建新的请求上下文
huli@hudeMacBook-Pro cache % curl -i localhost:4000/redirect
HTTP/1.1 200 OK
Server: openresty/1.21.4.1
Date: Thu, 21 Jul 2022 05:03:09 GMT
Content-Type: application/octet-stream
Transfer-Encoding: chunked
Connection: keep-alive
age: new 21
new name ==> 海贼王