本文基于Centos8进行实践,请读者自行安装OpenResty。
进入默认安装路径
cd /usr/local/openresty/nginx/conf
vim nginx.conf
location /sum {
# 只允许内部调用
internal;
content_by_lua_block {
local args = ngx.req.get_uri_args()
ngx.print(tonumber(args.a) + tonumber(args.b))
}
}
location /multi {
content_by_lua_block {
local start_time = ngx.now()
local res1, res2 = ngx.location.capture_multi( {
{"/sum", {args={a=3, b=8}}},
{"/sum", {args={a=3, b=8}}}
})
ngx.say("status:", res1.status, " response:", res1.body)
ngx.say("status:", res2.status, " response:", res2.body)
ngx.say("time used:", ngx.now() - start_time)
}
}
location /exec {
content_by_lua_block {
ngx.exec("/sum?a=6&b=8")
}
}
ngx.redirect为重定向,比如访问baidu.com会重定向https://baidu.com,
ngx.exec方法与ngx.redirect是完全不同的,前者纯粹内部跳转并且没有引入任何额外 HTTP信号
location /print_param {
content_by_lua_block {
local arg = ngx.req.get_uri_args()
for k,v in pairs(arg) do
ngx.say("[GET ] key:", k, " v:", v)
end
ngx.req.read_body()
local arg = ngx.req.get_post_args()
for k,v in pairs(arg) do
ngx.say("[POST] key:", k, " v:", v)
end
}
}
location /test {
content_by_lua_block {
local res = ngx.location.capture(
'/print_param',
{
method = ngx.HTTP_POST,
args = ngx.encode_args({a = 1, b = '2&'}),
body = ngx.encode_args({c = 3, d = '4&'})
}
)
ngx.say(res.body)
}
}
# 默认读取 body
lua_need_request_body on;
location /get_body_data {
content_by_lua_block {
local data = ngx.req.get_body_data()
ngx.say("hello ", data)
}
}
ngx.say 与 ngx.print 均为异步输出
如何优雅处理响应体过大的输出?
如果响应体比较小,这时候相对就比较随意,但是如果响应体过大,是不能直接调用 API 完成响应体输出的。响应体过大,分两种情况:
① 输出内容本身体积很大,例如大文件下载
② 输出内容本身是由各种碎片拼凑的,碎片数量庞大,例如应答数据是某地区所有地址数据
第①个情况,要利用HTTP 1.1特性CHUNKED编码来完成,利用 CHUNKED 格式,把一个大的响应体拆分成多个小的应答体,分批、有节制的响应给请求方
# 开启chunked编码
chunked_transfer_encoding on;
location /download_large_file {
content_by_lua_block {
-- ngx.var.limit_rate = 1024*1024
local file, err = io.open(ngx.config.prefix() .. "data.db","r")
if not file then
ngx.log(ngx.ERR, "open file error:", err)
ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
end
local data
while true do
data = file:read(1024*1024)
if nil == data then
break
end
ngx.print(data)
ngx.flush(true)
end
file:close()
}
}
我们在/usr/local/openresty/nginx
目录下准备data.db文件,按块读取本地文件内容(每次1MB),并以流式方式进行响应。
第②个情况,其实就是要利用 ngx.print 的特性了,它的输入参数可以是单个或多个字符串参数,也可以是 table 对象
local table = {
"hello, ",
{"world: ", true, " or ", false,
{": ", nil}}
}
ngx.print(table)
将输出:
hello, world: true or false: nil
也就是说当有非常多碎片数据时,没有必要一定连接成字符串后再进行输出。完全可以直接存放在 table 中,用数组的方式把这些碎片数据统一起来,直接调用 ngx.print(table) 即可。这种方式效率更高,并且更容易被优化
欢迎关注公众号算法小生