body_filter_by_lua
------------------
**语法:** *body_filter_by_lua <lua-script-str>*
**环境:** *http, server, location, location if*
**阶段:** *output-body-filter*
使用`<lua-script-str>`指定的 Lua 代码定义一个输出应答体过滤器。
输入数据块是 [ngx.arg](#ngxarg)\[1\](Lua的字符串形式),结束标识"eof"是应答体数据最后一位[ngx.arg](#ngxarg)\[2\](Lua的布尔值形式)。
在这个场景下,结束标识"eof"仅仅是 Nginx chain 缓冲区的`last_buf`(主请求)或`last_in_chain`(子请求)。(在`v0.7.14`版本之前,结束标识"eof"在子请求中是完全不能使用的。)
使用下面 Lua 代码,可以对输出数据流立即终止:
```lua
return ngx.ERROR
```
这样截断响应体,通常导致结果不完整的,也是无效的响应。
本指令的 Lua 代码可以使用 Lua 字符串或字符串的表重写[ngx.arg](#ngxarg)\[1\]输入数据块内容,从而完成 Nginx 输出体下游过滤数据修改。例如,在输出体转换所有的小写字母,我们可以这样用:
```nginx
location / {
proxy_pass http://mybackend;
body_filter_by_lua 'ngx.arg[1] = string.upper(ngx.arg[1])';
}
```
当设置`nil`或一个空的 Lua 字符串值给`ngx.arg[1]`,将没有任何数据块下发到 Nginx 下游。
同样,新的结束标识"eof"也可以通过对[ngx.arg](#ngxarg)\[2\]设定一个布尔值。例如:
```nginx
location /t {
echo hello world;
echo hiya globe;
body_filter_by_lua '
local chunk = ngx.arg[1]
if string.match(chunk, "hello") then
ngx.arg[2] = true -- new eof
return
end
-- just throw away any remaining chunk data
ngx.arg[1] = nil
';
}
```
然后 `GET /t` 将返回下面的结果:
hello world
就是说,当应答体过滤发现一个块包含关键字"hello",它将立即设置结束标识"eof"为 true ,应答内容被截断尽管后面还有有效数据。
当Lua代码可能改变应答体的长度时,我们必须总是清空响应头中的`Content-Length`(如果有),强制使用流式输出,如:
```nginx
location /foo {
# fastcgi_pass/proxy_pass/...
header_filter_by_lua 'ngx.header.content_length = nil';
body_filter_by_lua 'ngx.arg[1] = string.len(ngx.arg[1]) .. "\\n"';
}
```
注意:下面这些API函数在这个环境中是禁用的,这受制于当前 Nginx 输出过滤器的实现:
* 输出API函数类(例如:[ngx.say](#ngxsay) 和 [ngx.send_headers](#ngxsend_headers))
* 控制API函数类(例如:[ngx.exit](#ngxexit) 和 [ngx.exec](#ngxexec))
* 子请求函数类(例如:[ngx.location.capture](#ngxlocationcapture) 和 [ngx.location.capture_multi](#ngxlocationcapture_multi))
* cosocket 函数类(例如:[ngx.socket.tcp](#ngxsockettcp) 和 [ngx.req.socket](#ngxreqsocket))
Nginx 输出过滤器在一个单独请求中可能被调用多次,因为应答体可能使用块的方式进行投递。所以,本指令中的 Lua 代码在这个单独的HTTP请求生命周期内,同样会执行多次。
该指令在`v0.5.0rc32`版本中首次引入。
[返回目录](#directives)
> English source:
body_filter_by_lua
------------------
**syntax:** *body_filter_by_lua <lua-script-str>*
**context:** *http, server, location, location if*
**phase:** *output-body-filter*
Uses Lua code specified in `<lua-script-str>` to define an output body filter.
The input data chunk is passed via [ngx.arg](#ngxarg)\[1\] (as a Lua string value) and the "eof" flag indicating the end of the response body data stream is passed via [ngx.arg](#ngxarg)\[2\] (as a Lua boolean value).
Behind the scene, the "eof" flag is just the `last_buf` (for main requests) or `last_in_chain` (for subrequests) flag of the Nginx chain link buffers. (Before the `v0.7.14` release, the "eof" flag does not work at all in subrequests.)
The output data stream can be aborted immediately by running the following Lua statement:
```lua
return ngx.ERROR
```
This will truncate the response body and usually result in incomplete and also invalid responses.
The Lua code can pass its own modified version of the input data chunk to the downstream Nginx output body filters by overriding [ngx.arg](#ngxarg)\[1\] with a Lua string or a Lua table of strings. For example, to transform all the lowercase letters in the response body, we can just write:
```nginx
location / {
proxy_pass http://mybackend;
body_filter_by_lua 'ngx.arg[1] = string.upper(ngx.arg[1])';
}
```
When setting `nil` or an empty Lua string value to `ngx.arg[1]`, no data chunk will be passed to the downstream Nginx output filters at all.
Likewise, new "eof" flag can also be specified by setting a boolean value to [ngx.arg](#ngxarg)\[2\]. For example,
```nginx
location /t {
echo hello world;
echo hiya globe;
body_filter_by_lua '
local chunk = ngx.arg[1]
if string.match(chunk, "hello") then
ngx.arg[2] = true -- new eof
return
end
-- just throw away any remaining chunk data
ngx.arg[1] = nil
';
}
```
Then `GET /t` will just return the output
hello world
That is, when the body filter sees a chunk containing the word "hello", then it will set the "eof" flag to true immediately, resulting in truncated but still valid responses.
When the Lua code may change the length of the response body, then it is required to always clear out the `Content-Length` response header (if any) in a header filter to enforce streaming output, as in
```nginx
location /foo {
# fastcgi_pass/proxy_pass/...
header_filter_by_lua 'ngx.header.content_length = nil';
body_filter_by_lua 'ngx.arg[1] = string.len(ngx.arg[1]) .. "\\n"';
}
```
Note that the following API functions are currently disabled within this context due to the limitations in NGINX output filter's current implementation:
* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers))
* Control API functions (e.g., [ngx.exit](#ngxexit) and [ngx.exec](#ngxexec))
* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi))
* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)).
Nginx output filters may be called multiple times for a single request because response body may be delivered in chunks. Thus, the Lua code specified by in this directive may also run multiple times in the lifetime of a single HTTP request.
This directive was first introduced in the `v0.5.0rc32` release.
[Back to TOC](#directives)
- Name yuansheng-8.4 WenMing(√)
- Status yuansheng-8.6 WenMing(√)
- Version
- Synopsis yuansheng-8.6 WenMing(√)
- Description yuansheng-8.16 WenMing(√)
- Typical Uses yuansheng-8.16 WenMing(√)
- Nginx Compatibility yuansheng-8.17 WenMing(√)
- Installation yuansheng-8.17 WenMing(√)
- C Macro Configurations yuansheng-8.17 WenMing(√)
- Installation on Ubuntu 11.10 yuansheng-8.18
- Community
- English Mailing List
- Chinese Mailing List
- Code Repository yuansheng-8.20 WenMing(√)
- Bugs and Patches yuansheng-8.20 WenMing(√)
- Lua/LuaJIT bytecode support yuansheng-8.31
- System Environment Variable Support yuansheng-9.1
- HTTP 1.0 support lance-2015.8.13
- Statically Linking Pure Lua Modules yuansheng-9.1
- Nginx Worker内的数据共享 lance-2015.8.5
- Known Issues
- TCP socket connect operation issues yuansheng-9.2
- Lua Coroutine Yielding/Resuming yuansheng-9.2
- Lua Variable Scope yuansheng-9.2
- Locations Configured by Subrequest Directives of Other Modules lance-2015.8.12
- Cosockets Not Available Everywhere yuansheng-9.2
- 特别转义序列 lance-2015.8.5
- Mixing with SSI Not Supported yuansheng-9.2
- SPDY Mode Not Fully Supported yuansheng-9.2
- Missing data on short circuited requests yuansheng-9.2
- TODO yuansheng-9.3
- Changes yuansheng-9.3 WenMing(√)
- Test Suite yuansheng-9.3
- Copyright and License yuansheng-9.3
- See Also yuansheng-9.3
- Directives yuansheng-9.3
- Nginx API for Lua yuansheng-9.3
- Obsolete Sections yuansheng-9.3
- lua_use_default_type hambut 2015.8.5
- lua_code_cache hambut 2015.8.5
- lua_regex_cache_max_entries yuansheng-9.3
- lua_regex_match_limit yuansheng-9.3
- lua_package_path yuansheng-9.4
- lua_package_cpath yuansheng-9.4
- init_by_lua yuansheng-9.4
- init_by_lua_file yuansheng-9.4
- init_worker_by_lua yuansheng-9.6
- init_worker_by_lua_file yuansheng-9.6
- set_by_lua yuansheng-9.6
- set_by_lua_file yuansheng-9.6
- content_by_lua dengshiyong 2015.8.12 WenMing(√)
- content_by_lua_file yuansheng-9.19
- rewrite_by_lua yuansheng-9.19
- rewrite_by_lua_file yuansheng-9.19
- access_by_lua yuansheng-9.27
- access_by_lua_file yuansheng-9.28
- header_filter_by_lua liujinxuan 2015.9.1
- header_filter_by_lua_file yuansheng-9.28
- body_filter_by_lua yuansheng-9.28
- body_filter_by_lua_file yuansheng-9.28
- log_by_lua yuansheng-9.28
- log_by_lua_file yuansheng-9.28
- lua_need_request_body yuansheng-9.28
- lua_shared_dict lance-2015.8.20
- lua_socket_connect_timeout yuansheng-9.28
- lua_socket_send_timeout yuansheng-9.28
- lua_socket_send_lowat yuansheng-9.28
- lua_socket_read_timeout yuansheng-9.28
- lua_socket_buffer_size yuansheng-9.28
- lua_socket_pool_size yuansheng-9.28
- lua_socket_keepalive_timeout yuansheng-9.28
- lua_socket_log_errors yuansheng-9.28
- lua_ssl_ciphers yuansheng-9.29
- lua_ssl_crl yuansheng-9.29
- lua_ssl_protocols yuansheng-9.29
- lua_ssl_trusted_certificate yuansheng-9.29
- lua_ssl_verify_depth yuansheng-9.29
- lua_http10_buffering yuansheng-9.29
- rewrite_by_lua_no_postpone yuansheng-9.29
- lua_transform_underscores_in_response_headers yuansheng-9.29
- lua_check_client_abort yuansheng-9.29
- lua_max_pending_timers yuansheng-9.29
- lua_max_running_timers yuansheng-9.29
- ngx.arg lance-2015.8.19
- ngx.var.VARIABLE lance-2015.8.19
- Core constants lance-2015.8.14 WenMing(√)
- HTTP method constants lance-2015.8.13
- HTTP status constants lance-2015.8.13
- Nginx log level constants lance-2015.8.13
- print lance-2015.8.14
- ngx.ctx lance-2015.8.14
- ngx.location.capture lance-2015.8.11
- ngx.location.capture_multi lance-2015.8.11
- ngx.status lance-2015.8.18 yuansheng(√)
- ngx.header.HEADER lance-2015.9.6 yuansheng(√)
- ngx.resp.get_headers lance-2015.9.7 yuansheng(√)
- ngx.req.start_time lance-2015.9.9 yuansheng(√)
- ngx.req.http_version lance-2015.9.9 yuansheng(√)
- ngx.req.raw_header lance-2015.9.9 yuansheng(√)
- ngx.req.get_method lance-2015.9.9 yuansheng(√)
- ngx.req.set_method lance-2015.9.9 yuansheng(√)
- ngx.req.set_uri lance-2015.9.9
- ngx.req.set_uri_args lance-2015.9.10
- ngx.req.get_uri_args lance-2015.9.10
- ngx.req.get_post_args lance-2015.9.10
- ngx.req.get_headers lance-2015.9.11
- ngx.req.set_header lance-2015.9.14
- ngx.req.clear_header lance-2015.9.14
- ngx.req.read_body lance-2015.9.16
- ngx.req.discard_body lance-2015.9.24
- ngx.req.get_body_data lance-2015.9.24
- ngx.req.get_body_file lance-2015.9.28
- ngx.req.set_body_data lance-2015.9.28
- ngx.req.set_body_file lance-2015.9.28
- ngx.req.init_body lance-2015.9.28
- ngx.req.append_body lance-2015.9.28
- ngx.req.finish_body lance-2015.9.28
- ngx.req.socket yuansheng-10.12
- ngx.exec yuansheng-10.12
- ngx.redirect yuansheng-10.12
- ngx.send_headers yuansheng-10.12
- ngx.headers_sent yuansheng-10.12
- ngx.print lance-2015.8.7
- ngx.say lance-2015.8.7
- ngx.log lance-2015.8.13
- ngx.flush lance-2015.8.13
- ngx.exit lance-2015.8.13
- ngx.eof lance-2015.8.18
- ngx.sleep lance-2015.8.18
- ngx.escape_uri lance-2015.8.18
- ngx.unescape_uri lance-2015.8.18
- ngx.encode_args lance-2015.8.18
- ngx.decode_args lance-2015.8.18
- ngx.encode_base64 hambut-2015.9.9
- ngx.decode_base64 hambut-2015.9.9
- ngx.crc32_short hambut-2015.9.9
- ngx.crc32_long hambut-2015.9.9
- ngx.hmac_sha1 hambut-2015.9.9
- ngx.md5 hambut-2015.9.9
- ngx.md5_bin hambut-2015.9.9
- ngx.sha1_bin hambut-2015.9.9
- ngx.quote_sql_str hambut-2015.9.9
- ngx.today bells-2015.8.8
- ngx.time bells-2015.8.22
- ngx.now bells-2015.8.22
- ngx.update_time bells-2015.8.16
- ngx.localtime bells-2015.8.22
- ngx.utctime bells-2015.8.22
- ngx.cookie_time yuansheng-10.12
- ngx.http_time yuansheng-10.10
- ngx.parse_http_time yuansheng-10.10
- ngx.is_subrequest yuansheng-10.8
- ngx.re.match lance-2015.8.6
- ngx.re.find lance-2015.8.6
- ngx.re.gmatch lance-2015.8.6
- ngx.re.sub lance-2015.8.6
- ngx.re.gsub lance-2015.8.6
- ngx.shared.DICT lance-2015.8.10
- ngx.shared.DICT.get lance-2015.8.10
- ngx.shared.DICT.get_stale lance-2015.8.10
- ngx.shared.DICT.set lance-2015.8.10
- ngx.shared.DICT.safe_set lance-2015.8.10
- ngx.shared.DICT.add lance-2015.8.10
- ngx.shared.DICT.safe_add lance-2015.8.10
- ngx.shared.DICT.replace lance-2015.8.10
- ngx.shared.DICT.delete lance-2015.8.10
- ngx.shared.DICT.incr lance-2015.8.10
- ngx.shared.DICT.flush_all lance-2015.8.10
- ngx.shared.DICT.flush_expired lance-2015.8.10
- ngx.shared.DICT.get_keys lance-2015.8.10
- ngx.socket.udp yuansheng-10.8
- udpsock:setpeername yuansheng-10.8
- udpsock:send yuansheng-10.8
- udpsock:receive yuansheng-10.8
- udpsock:close yuansheng-10.8
- udpsock:settimeout yuansheng-10.8
- ngx.socket.tcp yuansheng-10.7
- tcpsock:connect yuansheng-10.7
- tcpsock:sslhandshake yuansheng-10.7
- tcpsock:send yuansheng-10.7
- tcpsock:receive yuansheng-10.5
- tcpsock:receiveuntil yuansheng-10.5
- tcpsock:close yuansheng-10.5
- tcpsock:settimeout yuansheng-10.5
- tcpsock:setoption yuansheng-10.5
- tcpsock:setkeepalive yuansheng-10.5
- tcpsock:getreusedtimes yuansheng-10.5
- ngx.socket.connect yuansheng-10.4
- ngx.get_phase yuansheng-10.2
- ngx.thread.spawn yuansheng-10.2
- ngx.thread.wait yuansheng-10.4
- ngx.thread.kill yuansheng-10.4
- ngx.on_abort yuansheng-10.2
- ngx.timer.at yuansheng-10.1
- ngx.config.debug yuansheng-9.30
- ngx.config.prefix yuansheng-9.30
- ngx.config.nginx_version yuansheng-9.30
- ngx.config.nginx_configure yuansheng-9.30
- ngx.config.ngx_lua_version yuansheng-9.30
- ngx.worker.exiting yuansheng-9.30
- ngx.worker.pid yuansheng-9.30
- ndk.set_var.DIRECTIVE yuansheng-9.30
- coroutine.create yuansheng-9.30
- coroutine.resume yuansheng-9.30
- coroutine.yield yuansheng-9.30
- coroutine.wrap yuansheng-9.30
- coroutine.running yuansheng-9.30
- coroutine.status yuansheng-9.30