内容响应阶段

一)header_filter_by_lua

语法:

header_filter_by_lua <lua-script-str>

语境:http,server,location,location if

阶段:output-header-filter 一般用来设置cookie和headers,在该阶段不能使用如下几个API:

  • 1、output API(ngx.say和ngx.send_headers)

  • 2、control API(ngx.exit和ngx.exec)

  • 3、subrequest API(ngx.location.capture和ngx.location.capture_multi)

  • 4、cosocket API(ngx.socket.tcp和ngx.req.socket)

案例一:

location / {
    header_filter_by_lua 'ngx.header.Foo = "blah"'; 
    echo "Hello World!";
}

案例二:

http {  
  
    log_format  main  '$msec $status $request $request_time '  
                      '$http_referer $remote_addr [ $time_local ] '  
                      '$upstream_response_time $host $bytes_sent '  
                      '$request_length $upstream_addr';  
  
    access_log  logs/access.log main buffer=32k flush=1s;  
  
    upstream remote_world {  
        server 127.0.0.1:8080;  
    }  
  
    server {  
        listen 80;  
  
        location /exec {  
            content_by_lua '  
                local cjson = require "cjson"  
                local headers = {  
                    ["Etag"] = "662222165e216225df78fbbd47c9333",  
                    ["Last-Modified"] = "Fri, 12 May 2018 12:22:22 GMT",  
                }  
                ngx.var.my_headers = cjson.encode(headers)  
                ngx.var.my_upstream = "remote_world"  
                ngx.var.my_uri = "/world"  
                ngx.exec("/upstream")  
            ';  
        }  
  
        location /upstream {  
            internal;  
  
            set $my_headers $my_headers;  
            set $my_upstream $my_upstream;  
            set $my_uri $my_uri;  
            proxy_pass http://$my_upstream$my_uri;  
  
            header_filter_by_lua '  
                local cjson = require "cjson"  
                headers = cjson.decode(ngx.var.my_headers)  
                for k, v in pairs(headers) do  
                    ngx.header[k] = v  
                end  
            ';  
        }  
    }  
  
  
    server {  
        listen 8080;  
  
        location /world {  
            echo "hello world";  
        }  
    }  
} 

二)body_filter_by_lua

语法:

语境:http,server,location,location if

阶段:output-body-filter

输入的数据时通过ngx.arg[1](作为lua的string值),通过ngx.arg[2]这个bool类型表示响应数据流的结尾。

这个指令可以用来篡改http的响应正文的;会调用几次 在该阶段不能利用如下几个API:

  • 1、output API(ngx.say和ngx.send_headers)

  • 2、control API(ngx.exit和ngx.exec)

  • 3、subrequest API(ngx.location.capture和ngx.location.capture_multi)

  • 4、cosocket API(ngx.socket.tcp和ngx.req.socket)

输入的数据时通过ngx.arg[1](作为lua的string值),通过ngx.arg[2]这个bool范例暗示响应数据流的末了。 基于这个原因,’eof’只是nginx的链接缓冲区的last_buf(对主requests)或last_in_chain(对subrequests)的标志。 运行以下呼吁可以当即终止运行接下来的lua代码

这会将响应体截断导致无效的响应。lua代码可以通过修改ngx.arg[1]的内容将数据传输到下游的 nginx output body filter阶段的其它模块中去。譬喻,将response body中的小写字母举办反转,我们可以这么写:

案例一

尽管只有两个 echo,但是 body_filter_by_lua* 会被调用三次!

第三次调用的时候,ngx.arg[1] 为空字符串,而 ngx.arg[2] 为 true。 这是因为,Nginx 的 upstream 相关模块,以及 OpenResty 的 content_by_lua, 会单独发送一个设置了 last_buf 的空 buffer,来表示流的结束。这算是一个约定俗成的惯例,所以有必要在运行相关逻辑之前, 检查 ngx.arg[1] 是否为空。当然反过来不一定成立,ngx.arg[2] == true 并不代表 ngx.arg[1] 一定为空。

案例二

这是因为,当body filter看到了一块包括”hello“的字符块后当即将”eof“标志配置为了true, 从而导致响应被截断了但仍然是有效的回覆。

Last updated

Was this helpful?