lua-resty-http上传数据

lua-resty-http上传数据

lua-resty-http是一个基于Openresty/ngx_lua的HTTP客户端,支持POST方法上传数据。用法很简单。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
            content_by_lua_block {
                local http = require "resty.http"
                local httpc = http:new()
                
                local res = httpc:request_uri("http://www.baidu.com/", {
                        method = "POST",
                        body= "Hello, Lua!",
                        headers = {
                            ["User-Agent"] = "lua-resty-http",
                        }
                    })
                if not res then
                    return
                end
                ngx.log(ngx.ERR, "status: ", res.status)
                
            }

request_uri这个方法用于向http://www.baidu.com/发送POST请求,包体内容为”Hello, Lua!”。

HTTP中传输包体

HTTP协议中,有包体需要发送时,需要有方法标识包体的结束,这样对方才能判断是否接收到了完整的包体。判断方法有两个。

  • 包体的长度确定时,HTTP请求头部有Content-Length字段,标记包体的长度
  • 包体长度不确定时,使用分块传输。请求头部有”Transfer-Encoding:chunked”表示传输包体是chunked编码的

对于lua-resty-http, 通过request_uri发送请求时包体的内容由参数中的body指定。body可以是一个lua字符串或者lua中的table。

  • body为字符串时,包体长度为字符串长度,lua-resty-http会为请求添加Content-Length字段,标记包体的长度
  • body为table时,lua-resty-http不会添加Content-Length头部,也不会为进行chunked编码,而是直接将table中所有成员组合成字符串发送出去

若要通过lua-resty-http以chunked编码上传数据,必须自己为数据进行chunked编码。

chunked编码

如果一个HTTP消息(请求消息或应答消息)的Transfer-Encoding消息头的值为chunked,那么,消息体由数量未定的块组成,并以最后一个大小为0的块为结束。

每一个非空的块都以该块包含数据的字节数(字节数以十六进制表示)开始,跟随一个CRLF (回车及换行),然后是数据本身,最后块CRLF结束。在一些实现中,块大小和CRLF之间填充有白空格(0x20)。

最后一块是单行,由块大小(0),一些可选的填充白空格,以及CRLF。最后一块不再包含任何数据,但是可以发送可选的尾部,包括消息头字段。

消息最后以CRLF结尾。

例如包体为”Hello, Lua!”,长度为10, 转换成16进制为a,则编码后的结果为”a\r\nHello,Lua!\r\n0\r\n\r\n”,最后面跟的”0\r\n\r\n”没有包含任何数据,只是表示包体结束。

lua-resty-http 上传chunked编码数据

利用lua-resty-http以chunked编码上传数据,需要手动进行chunked编码,同时设置Transfer-Encoding头部。

下面是一个示例,为了简单直接通过string.rep生成一个长字符串作为包体,string.format(“%x”, #raw_data)将字符串长度转换为十六进制格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
            content_by_lua_block {
                local http = require "resty.http"
                local httpc = http:new()
                local raw_data = string.rep("asdfgh", 512)
                local chunked = {
                    string.format("%x", #raw_data),
                    "\r\n",
                    raw_data,
                    "\r\n",
                    "0\r\n\r\n",
                }
                
                local res = httpc:request_uri("http://www.baidu.com/", {
                        method = "POST",
                        body= chunked,
                        headers = {
                            ["User-Agent"] = "lua-resty-http",
                            ["Transfer-Encoding"] = "chunked",
                        }
                    })
                if not res then
                    return
                end
                ngx.log(ngx.ERR, "status: ", res.status)
                
            }