在10.1节和10.2节,介绍的都是全局的缓存系统,那么有没有只针对当前请求设置的缓存呢,即某个数据在请求的每个阶段都有缓存,但请求结束缓存就会消失。
举例来说,请求在rewrite阶段生成1个缓存数据,作用是可以让后面的阶段(如content阶段)获取到该缓存数据,但该数据在请求完成后就没有用了,可以在请求结束后清除掉。
这种缓存主要针对如下情况使用,在Ngx_Lua中Lua API的执行是有阶段限制的,那么当某个不能执行Lua API的阶段需要使用Lua API指令生成数据时,就可以利用刚才介绍的缓存方式,在其他阶段处理好数据并缓存,在需要该数据的阶段调用此缓存即可。这里需要用到的缓存指令是ngx.ctx。
10.3.1 ngx.ctx的使用
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
含义:ngx.ctx是Lua的table类型,用来缓存基于Lua的环境数据,该缓存在请求结束后会随之清空,类似于Nginx中set指令的效果。
示例:
rewrite_by_lua_block {
--设置1个test数据
ngx.ctx.test = 'nginx'
ngx.ctx.test_1 = {a=1,b=2}
}
access_by_lua_block {
--修改test
ngx.ctx.test = ngx.ctx.test .. ' hello'
}
content_by_lua_block {
--输出test 和 test_1中的a元素的值
ngx.say(ngx.ctx.test)
ngx.say("a: ",ngx.ctx.test_1["a"])
}
header_filter_by_lua_block {
--作为响应头输出
ngx.header["test"] = ngx.ctx.test .. ' world!'
}
}
上述配置执行结果如下:
# curl -i 'http://testnginx.com/'
HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Mon, 18 Jun 2018 05:07:15 GMT
Content-Type: application/octet-stream
Transfer-Encoding: chunked
Connection: keep-alive
test: nginx hello world!
nginx hello
a: 1
从执行结果可知,ngx.ctx的数据可以被Lua的每个执行阶段读/写,并且支持存储table类型的数据。
10.3.2 子请求和内部重定向的缓存区别
ngx.ctx在子请求和内部重定向中的使用方法有些区别。在子请求中修改ngx.ctx. 的数据不会影响主请求中ngx.ctx.对应的数据,它们维护的是不同的版本,如执行子请求的ngx.location.capture、ngx.location.capture_multi、echo_location等指令时;在内部重定向中修改数据会破坏原始请求中ngx.ctx.*的数据,新请求将会是1个空的ngx.ctx table,例如,当ngx.exec、rewrite配合last/break使用时。
ngx.ctx在内部重定向中使用的示例如下:
location /subq {
header_filter_by_lua_block {
--如果ngx.ctx.test不存在,则把not test赋值给a
local a = ngx.ctx.test or 'not test'
--作为响应头输出
ngx.header["test"] = a .. ' world!'
}
content_by_lua_block {
ngx.say(ngx.ctx.test)
}
}
location / {
header_filter_by_lua_block {
ngx.header["test"] = ' world!'
}
content_by_lua_block {
ngx.ctx.test = "nginx"
--执行内部重定向
ngx.exec("/subq")
}
}
执行结果如下:
# curl -i 'http://testnginx.com/'
HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Mon, 18 Jun 2018 05:36:38 GMT
Content-Type: application/octet-stream
Transfer-Encoding: chunked
Connection: keep-alive
test: not test world!
nil
从执行结果可知,ngx.ctx.test在内部重定向后变为空。
注意:查询ngx.ctx 会产生元方法调用,这会消耗一定的服务器资源,所以如果数据可以通过函数生成,就尽量不要使用ngx.ctx。如果希望更多地了解ngx.ctx对性能的影响,可以通过火焰图对它的性能进行分析(详见第16章)。