【openresty】【子请求】使用capture进行子请求(一)

上一节介绍了,当有请求http://127.0.0.1/userid/play/live/01.m3u8进入时,如何通过content_by_lua进行url解析,并返回一个ts信息。但在实际使用中,ts信息一般是放在后台服务器上的。这个时候,就要在原有的请求中,发起一个子请求。

谈到子请求,我们先从capture认识子请求的基本面貌。从官方文档看到,https://github.com/openresty/lua-nginx-module#ngxlocationcapture

可以看到小demo如下,

 location /other {
     set $dog "$dog world";
     echo "$uri dog: $dog";
 }

 location /lua {
     set $dog 'hello';
     content_by_lua_block {
         res = ngx.location.capture("/other",
             { copy_all_vars = true })

         ngx.print(res.body)
         ngx.say(ngx.var.uri, ": ", ngx.var.dog)
     }
 }

好,参考上面的小demo,在上一节check.lua中,请求m3u8的地方,我们去后台请求m3u8,增加下面的逻辑,

                --m[3]来自请求url中的01.m3u8部分
                   local reqm3u8=string.format('/upstream/%s',m[3])
                ngx.log(ngx.NOTICE,reqm3u8)
                --get m3u8 info from upstream by subrequest
          local res = ngx.location.capture(reqm3u8,
            {
                 method = ngx.HTTP_GET,
                share_all_vars = true,
                body = reqm3u8
            }
        )

在nginx.conf中增加下面逻辑,

  upstream get_m3u8 {
            server 127.0.0.1:8080;
        }
        
       location /upstream
        {
        set $my_upstream "get_m3u8";

        rewrite_by_lua_block {
        ngx.log(ngx.ERR, ngx.req.raw_header());
        ngx.log(ngx.ERR,ngx.var.request_uri,ngx.var.request_body);
        ngx.log(ngx.ERR,"req_body,test:",ngx.var.request_body);
        local m,err=ngx.re.match(ngx.var.request_body, "/(.*)/(.*)")
        local requri=string.format('/m3u8_v2/%s',m[2]);
        ngx.req.set_uri(requri);
        ngx.log(ngx.ERR,"requri,test:",requri);
        }

        proxy_pass http://$my_upstream;

        }

  server {
            listen 8080;
            location /m3u8_v2 {
#                echo ngx.var.request_uri;
                 content_by_lua 'ngx.say(ngx.var.request_uri)';
            }

            location /world {
                echo "world";
            }
        }

请求后,curl http://127.0.0.1/99/play/live/01.m3u8
/M3U8_V2/01.M3U8
 

即,初始请求 /99/play/live/01.m3u8,经过判断,需要执行一个m3u8的子请求操作,那么构造一个upstream/01.m3u8的子操作,重新进入location逻辑,然后进行一次proxy_pass的upstream请求。当然,在此location中,因为后端服务器也用nginx模拟的(下一节制作一个真实的后台server),构造了一个8080端口拉起的服务,m3u8_v2服务。8080这个服务不是必须的,可以用sock服务或者python起一个非nginx的server。

这里遇到了几个细节需要关注:

1、子请求执行location /upstream中如何获取subrequest请求url

因为ngx.location.capture中,构造的subrequest,会把初始的req_uri信息 99/play/live/01.m3u8,原封不动的传导到子请求执行location /upstream中。此时ngx.var.request_uri的信息如下:

2021/02/14 06:31:27 [error] 6607#0: *122 [lua] rewrite_by_lua(nginx.conf:64):4: req_body,test:/upstream/01.m3u8, client: 127.0.0.1, server: localhost, request: "GET /99/play/live/01.m3u8 HTTP/1.1", subrequest: "/upstream/01.m3u8", host: "127.0.0.1"

那么,就需要在capture中,增加一个body的声明,body = reqm3u8,输出如上述日志,/upstream/01.m3u8

拿到subrequest操作后,就可以rewrite一下url,  ngx.req.set_uri(requri);

当然,如果是固定的url,参数从args里面取的,也可以在通过rewrite ^/upstream/(.*) /m3u8_v2/$1 ;直接重写url

2、ngx.log 打印中间变量的问题

https://www.iteye.com/blog/siyuan-zhu-2231016帖子给出一个很好的使用content语法的建议。

总结即,content_by_lua、proxy_pass、echo同属于content阶段函数,不能在一个location中同时使用。

那么我们在subrequest中用到了proxy_pass,就不能使用content_by_lua和echo。再考察其他lua执行阶段,比如 rewrite、access. 因为子请求不能使用access,所以,最终使用rewrite_by_lua_block ,来进行一些ngx.log的操作。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值