5.OpenResty系列之深入理解(一)

发布时间:2023年12月23日

本文基于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) 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
            }   
        }
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
        # 默认读取 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)
            }
        }

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*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) 即可。这种方式效率更高,并且更容易被优化

欢迎关注公众号算法小生

文章来源:https://blog.csdn.net/SJshenjian/article/details/135173932
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。