本文基于Centos8进行实践,请读者自行安装OpenResty。
1. 内部调用
进入默认安装路径
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))}}
2. 并行请求
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)} }
3. 流水线方式跳转
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信号
4. 获取GET与POST参数
location /print_param {content_by_lua_block {local arg = ngx.req.get_uri_args()for k,v in pairs(arg) dongx.say("[GET ] key:", k, " v:", v)endngx.req.read_body() local arg = ngx.req.get_post_args()for k,v in pairs(arg) dongx.say("[POST] key:", k, " v:", v)end} }
5. 在内部方法中传参
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)}}
6. 获取请求body
# 默认读取 bodylua_need_request_body on;location /get_body_data {content_by_lua_block {local data = ngx.req.get_body_data()ngx.say("hello ", data)}}
7. 输出响应体
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*1024local file, err = io.open(ngx.config.prefix() .. "data.db","r")if not file thenngx.log(ngx.ERR, "open file error:", err)ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)endlocal datawhile true dodata = file:read(1024*1024)if nil == data thenbreakendngx.print(data)ngx.flush(true)endfile: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) 即可。这种方式效率更高,并且更容易被优化
欢迎关注公众号算法小生