multipart/form-data 格式的http请求,以及lua构造实现

大多数前端工程师对于这个multipart/form-data并不陌生,当我们需要发送二进制数据如图片时,通常会用到这个玩意儿~我们用form表单提交数据时,会指定form元素的enctype属性值为multipart/form-data,又或者使用html5新对象Formdata,我们用ajax发送数据时会指定content-type为multipart/form-data.

  • multipart/form-data数据格式

我们来看看这个multipart/form-data究竟有什么特别之处。


Content-Type:multipart/form-data; boundary=ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Host: w.sohu.com
 
--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Content-Disposition: form-data;name="desc"
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
 
[......][......][......][......]...........................
--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Content-Disposition: form-data;name="pic"; filename="photo.jpg"
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
 
[图片二进制数据]
--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC--


以上是截取了一个典型的multipart/form-data格式的http请求的部分,我们逐行来分析。

首先第一行,很简单,指定了Content-Type值,表明了这条http请求是multipart/form-data类型的。
细心的你可能发现了有一个名为boundary的玩意儿,它的值是一串看起来毫无规律的字符串。
先不急,我们来看一下具体的数据~分析数据我们可以看到刚才提到的boundary值在数据体中重复出现了多次。没错,这个boundary就是用来分割不同数据块的,当你提交这个请求后,后台会根据你在content-type中指定的boundary值来解析你的数据。

Content-Disposition用来表明该数据是表单数据,name用来说明这块数据块的名称,当是二进制数据时,你还需指定filename,即文件名。

multipart/form-data对数据格式要求非常严格,换行时必须使用\r\n,而不是\n,分隔符boundary在使用时,必须加上"--",即--boundary\r\n,数据体完结后,用--boundary--表明结束

稍微介绍了multipart/form-data的相关知识,我们现在进入重点:使用Lua来构造multipart/form-data格式的数据,并与webserver交互(在这里使用php)

  • 我们需要使用到lua的一个模块,socket.http(安装引用不在本文讨论范围,请读者自行学习)

    local resbody = {}
    local reqfile= io.open(your-file-path)    
    local file_attr = lfs.attributes(your-file-path)
    local size = file_attr.size  --获取文件大小
    local  body, code, headers, status = http.request {
            method = "POST",
            url ='http://xxxx/upload.php',
            headers = {
                ["Content-Type"] =  "multipart/form-data",
                ["Content-Length"] = size
            },
            source = ltn12.source.file(reqfile),
            sink = ltn12.sink.table(respbody)
        }

注意,以上代码是我从stackoverflow上看到类似的,提问者自称能成功发送,但是这样的方式,在php里只能用file_get_contents( php://input )来获取原始数据流,但是$_POST和$_FILES数组拿不到你的数据,这显然不是我们想要的。


构造数据:
    local respbody = {}
    local _file = [[--abcd]]..'\r\n'..[[Content-Disposition: form-data; name="myfile"; filename="1.jpg"]]..'\r\n'..[[Content-Type: image/jpeg]]..'\r\n\r\n'
    local _table1 = '\r\n'..[[--abcd]]..'\r\n'..[[Content-Disposition: form-data; name="type";]]..'\r\n\r\n'..[[0]]
    local _table2 = '\r\n'..[[--abcd]]..'\r\n'..[[Content-Disposition: form-data; name="themeName";]]..'\r\n\r\n'..[[1482753000731]]
    local _end ='\r\n'..[[--abcd--]]..'\r\n'
    local reqfile= io.open(your-file-path)
    local file_attr = lfs.attributes(your-file-path)
    local size = file_attr.size
    local  body, code, headers, status = http.request {
        method = "POST",
        url = 'http://xxxx/upload.php',
        headers = {
            ["Content-Type"] =  "multipart/form-data;boundary=abcd",
            ["Content-Length"] = size+#_file+#_table1+#_table2+#_end
        },
        source = ltn12.source.cat(ltn12.source.string(_file),ltn12.source.file(reqfile),ltn12.source.string(_table1),ltn12.source.string(_table2),ltn12.source.string(_end)),
        sink = ltn12.sink.table(respbody)
    }

注意:我们这里进行了字符串块的拼接,ltn12.source.string()只能接受字符串块,这里的拼接过程中,换行符\r\n需要特别注意。

以上就是使用Lua构造multipar/form-data格式数据,并发送请求的全部内容,感谢阅读。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: openresty lua 可以通过 ngx.req.get_body_data() 函数来获取请求报文数据。如果请求报文是以 application/x-www-form-urlencoded 或 multipart/form-data 格式提交的,也可以通过 ngx.req.get_post_args() 函数来获取请求参数。如果请求报文是以 application/json 格式提交的,可以通过 ngx.req.get_body_data() 函数获取请求体数据,然后使用 json.decode() 函数将其解析为 Lua table。 ### 回答2: 要在OpenResty中接受请求报文数据,可以使用ngx.req模块。这个模块提供了处理请求内容的功能。 首先,我们可以使用ngx.req.get_method函数获取请求的方法,例如GET或POST。接下来,可以使用ngx.req.get_headers函数获取请求头的信息,例如User-Agent、Content-Type等。 要获取请求体的内容,可以使用ngx.req.read_body函数来读取请求体。然后,可以使用ngx.req.get_post_args函数来获取请求体的参数。如果请求体的类型是application/x-www-form-urlencoded,那么可以使用ngx.req.get_post_args函数直接获取参数。如果请求体是JSON格式,可以使用ngx.req.get_body_data函数获取请求体的原始数据,然后使用Lua中的json库进行解析。 另外,还可以使用ngx.req.get_uri_args函数来获取URL中的参数。这个函数返回一个Lua表,其中包含了URL中的所有参数。 除了获取请求报文数据,OpenResty还提供了ngx.req.set_header函数来设置请求头的信息。可以使用ngx.req.set_header函数来添加、修改或删除请求头的参数。 在处理完请求报文数据后,可以使用ngx.say函数来像客户端返回响应内容。可以将任何数据作为ngx.say函数的参数进行返回,包括字符串、数值、表等。 总结起来,通过ngx.req模块的函数,我们可以获取请求的方法、请求头、请求体、URL参数等请求报文数据,并且还可以设置请求头和返回响应内容。 ### 回答3: 在OpenResty中,可以通过使用ngx.req.get_body_data()方法接收请求报文数据。 ngx.req.get_body_data()方法用于获取请求报文主体的数据,并且可以在ngx_lua中方便地进行处理。 使用方法如下: local body_data = ngx.req.get_body_data() if body_data then -- 处理请求报文数据 -- ... else -- 请求报文没有主体数据 -- ... end 需要注意的是,ngx.req.get_body_data()方法只能获取请求报文中的主体数据,并不能获取请求报文的其他信息。如果需要获取其他请求信息,可以使用ngx.req.get_uri_args()获取查询参数,ngx.req.get_headers()获取请求头部信息,以及ngx.req.get_method()获取请求方法等。 在使用ngx.req.get_body_data()方法前,需要保证在nginx配置文件中已启用了请求体内容的接收。可以在http或server配置块中添加以下指令: http { # ... client_body_buffer_size 8k; client_max_body_size 8m; # ... } 以上是OpenResty Lua如何接收请求报文数据的方法。通过使用ngx.req.get_body_data()方法,我们可以方便地获取到请求报文的主体数据,并进行相应的处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值