使用 ngx_lua (openresty)正确读取 HTTP 请求 body

栏目: Lua · 发布时间: 5年前

内容简介:之前用 ngx_lua(openresty) 写了一个处理 HTTP 请求的程序,今天发现当发送的 HTTP 请求 body 很大的时候,发现老是报错,最后定位到于是我去 ngx_lua 的文档看第一条,我是读了文档的,知道要 Nginx 默认是不会读 body 的,要么打开读 body 的开关,要么显示调用一下 read。所以代码中已经调用了

之前用 ngx_lua(openresty) 写了一个处理 HTTP 请求的程序,今天发现当发送的 HTTP 请求 body 很大的时候,发现老是报错,最后定位到 ngx.req.get_body_data() 这个函数返回 nil ,而不是真正的 body。

于是我去 ngx_lua 的文档看 这个函数的文档 ,发现文档中说有三种情况下,这个函数的返回值会是 nil:

This function returns nil if

  1. the request body has not been read,
  2. the request body has been read into disk temporary files,
  3. or the request body has zero size.

第一条,我是读了文档的,知道要 Nginx 默认是不会读 body 的,要么打开读 body 的开关,要么显示调用一下 read。所以代码中已经调用了 ngx.req.read_body() 了,不会是这个原因。

第三条,也不可能,我通过 curl 发送的,body 肯定是发出去了(可以抓包验证)。

那么基本上就确定是这个 request body 被读到硬盘的临时文件里了。看到这里我猜应该是 Nginx 是将大的 HTTP 请求放到磁盘中而不是放到内存中。搜了一下 文档 ,发现有这个参数:

Syntax:	client_body_buffer_size size;
Default:	
client_body_buffer_size 8k|16k;
Context:	http, server, location

当请求体的大小大禹 client_body_buffer_size 的时候,Nginx 将会把它存到一个临时文件中,而不是放到内存中。这个值的大小默认是内存页的两倍:32 位系统上是 8k,64位系统上是16k。

OK,问题找到了,现在解决方案有两个:1)调大这个值,我觉得是不合理的,这样会浪费内存。2)可以想办法读到临时文件中的大 body。ngx_lua 提供了配套的方法 ngx_req.get_body_file ,注意这只是获得文件,还要在 lua 代码中打开读取文件。

所以最后,处理一个请求且还能正确处理很大 body 的请求的代码是这样的,其中高亮的部分,是核心的逻辑,先尝试从内存中读 body,如果读不到,就去临时文件中读。

    location /request_body {
        content_by_lua '
 
            function read_from_file(file_name)
                local f = assert(io.open(file_name, "r"))
                local string = f:read("*all")
                f:close()
                return string
            end
 
            ngx.req.read_body()
            local body_str = ngx.req.get_body_data()
            if nil == body_str then
                local body_file = ngx.req.get_body_file()
                if body_file then
                    body_str = read_from_file(body_file)
                end
            end
                
            ngx.say(body_str)
        ';  
    }

我读这个实际的应用场景是,读出 body,按照 json 解析出来当做路由规则(需求是需要动态设置 HTTP 的路由规则,所以我用 ngx_lua 在 nginx 上新开了个端口监控这样的规则)。现在用很大的规则一测试,发现性能下降很厉害。存到文件、再读出文件是一方面。另一方面是 ngx_lua 是为每一个 HTTP 请求开一个 lua 协程处理,不能共享变量,只能通过 lua_shared_dict 来保存持久的变量。但是 lua_shared_dict 的问题是,这个 dict 只支持 “Lua booleans, numbers, strings, or nil”,解析出来的 json 是一个 lua 的 table,不能保存到 lua_shared_dict 里面,我只好保存一个字符串,然后对每一个 HTTP 请求 json decode 这个字符串了。不知道有没有更好的方法。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

企业应用架构模式

企业应用架构模式

Martin Fowler / 王怀民、周斌 / 机械工业出版社 / 2010-4 / 59.00元

《企业应用架构模式》作者是当今面向对象软件开发的权威,他在一组专家级合作者的帮助下,将40多种经常出现的解决方案转化成模式,最终写成这本能够应用于任何一种企业应用平台的、关于解决方案的、不可或缺的手册。《企业应用架构模式》获得了2003年度美国软件开发杂志图书类的生产效率奖和读者选择奖。《企业应用架构模式》分为两大部分。第一部分是关于如何开发企业应用的简单介绍。第二部分是《企业应用架构模式》的主体......一起来看看 《企业应用架构模式》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

html转js在线工具
html转js在线工具

html转js在线工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试