在 Nginx 的典型应用场景中,几乎都是只读取 HTTP 头即可,例如负载均衡、正反向代理等场景。但是对于 API Server 或者 Web Application ,对 body 可以说就比较敏感了。
由于 OpenResty 基于 Nginx ,所以天然的对请求 body 的读取细节与其他成熟 Web 框架有些不同。在lua代码中使用 ngx.req.read_body 函数 (或打开 lua_need_request_body 选项强制本模块读取请求体,此方法不推荐)才可以获取到请求 body。究其原因,主要是 Nginx 诞生之初主要是为了解决负载均衡情况,而这种情况,是不需要读取 body 就可以决定负载策略的。
由于 Nginx 是为了解决负载均衡场景诞生的,所以它默认是不读取 body 的行为,会对 API Server 和 Web Application 场景造成一些影响。根据需要正确读取、丢弃 body 对 OpenResty 开发是至关重要的。
body 偶尔读取不到?
ngx.req.get_body_data() 读请求体,会偶尔出现读取不到直接返回 nil 的情况。
如果请求体尚未被读取,请先调用 ngx.req.read_body (或打开 lua_need_request_body 选项强制本模块读取请求体,此方法不推荐)。
如果请求体已经被存入临时文件,请使用 ngx.req.get_body_file 函数代替。
如需要强制在内存中保存请求体,请设置 client_body_buffer_size 和 client_max_body_size 为同样大小。
1、ngx.req.read_body
语法: ngx.req.read_body()
作用域: rewrite_by_lua*, access_by_lua*, content_by_lua*
开启获取请求中的body内容。
结论:
1、lua_need_request_body 开启后,该函数不执行。 2、如果在该函数前执行 ngx.req.discard_body(),该函数不执行。
2、ngx.req.discard_body
语法: ngx.req.discard_body()
作用域: rewrite_by_lua*, access_by_lua*, content_by_lua*
禁止获取请求中的body内容。
3、ngx.req.get_body_data
语法: data = ngx.req.get_body_data()
作用域: rewrite_by_lua*, access_by_lua*, content_by_lua*, log_by_lua*
获取请求body的内容,返回字符串。
注意:如果使用 ngx.req.get_post_args(),则返回一个lua table。
以下三种情况返回 nil:
- 未使用 ngx.req.read_body 读取请求 body,或未打开lua_need_request_body 。
- 请求 body 的内容已经写入临时文件;此时使用 ngx.req.get_body_file 获取,或设置 client_body_buffer_size 和 client_max_body_size同等大小,来避免请求body写入临时文件。
- 请求体的内容为空。
4、ngx.req.get_body_file
语法: file_name = ngx.req.get_body_file()
作用域: rewrite_by_lua*, access_by_lua*, content_by_lua*
返回请求body写入的临时文件。例如:返回
/usr/local/openresty/nginx/client_body_temp/0000000019
注意以下2种情况会写入临时文件:
1、请求body的长度超过nginx.conf定义的 client_body_buffer_size 大小。
2、nginx.conf开启 client_body_in_file_only on (请求body始终写入临时文件)
5、ngx.req.set_body_data
语法: ngx.req.set_body_data(data)
作用域: rewrite_by_lua*, access_by_lua*, content_by_lua*
设置请求body的内容,一般用于转发请求到子请求。
注意:
1、在使用该方法时,必需确保当前请求已经使用 ngx.req.read_body() 或者 lua_need_read_body on,否则,在使用该方法会报 500 错误。
例如:
ngx.req.read_body() --如果该行省略,将直接报错。 ngx.req.set_body_data("abc") ngx.exec("/app/detail")
6、ngx.req.set_body_file
语法: ngx.req.set_body_file(file_name, auto_clean?)
作用域: rewrite_by_lua*, access_by_lua*, content_by_lua*
7、ngx.req.init_body
语法: ngx.req.init_body(buffer_size?)
作用域: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*
8、ngx.req.append_body
语法: ngx.req.append_body(data_chunk)
作用域: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*
9、ngx.req.finish_body
语法: ngx.req.finish_body()
作用域: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*
Pingback引用通告: openResty中ngx_lua模块提供的API | 精彩每一天