大部分前端工程师对这个multipart/form-data并不陌生,当我们需要发送图片等二进制数据时,我们通常会用到这个东东~当我们使用form表单提交数据时,我们会指定form元素的enctype属性值为multipart/form-data,或者使用新的HTML5对象Formdata,而当我们使用ajax发送数据时,我们会指定content-typeasmultipart/form-data.multipart/form-data数据格式让我们来看看这个multipart/form-data有什么特别之处。内容类型:多部分/表单数据;boundary=ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXCHost:w.sohu.com--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC编码:8bit[...][...][...][...]....................--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXCContent-Disposition:form-data;name="pic";filename="photo.jpg"Content-Type:application/octet-streamContent-Transfer-Encoding:binary[图片二进制数据]--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC--以上是multipart/form-data格式的典型http请求的截取部分,我们逐行分析。首先,第一行很简单,指定Content-Type值,表示这个http请求是multipart/form-data类型。如果细心的话,你可能会发现有一个东西叫做boundary,它的值就是一串看似不规则的字符串。不着急,我们来看具体的数据~分析数据,我们可以看到刚才说的边界值在数据体中反复出现。没错,这个边界就是用来划分不同的数据块的。当你提交这个请求时,后台会根据你在content-type中指定的边界值来解析你的数据。Content-Disposition用来表示数据是表单数据,name用来表示这个数据块的名称。当是二进制数据时,还需要指定filename,即文件名。multipart/form-data对数据格式的要求非常严格。换行时必须使用\r\n而不是\n。使用分隔符边界时,必须加“--”,即--boundary\r\n,数据体结束后,用--boundary--表示结束。稍微介绍一下multipart/form-data的相关知识,现在进入重点:使用Lua构造multipart/form-data格式的数据,与webserver交互(这里使用php)我们需要用到一个模块oflua,socket.http(安装参考不在本文范围内,请自行学习)localresbody={}localreqfile=io.open(your-file-path)localfile_attr=lfs.attributes(your-file-path)localsize=file_attr.size--获取文件大小localbody,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数组是获取不到你的数据的,这显然不是我们想要的。构造数据:localrespbody={}local_file=[[--abcd]]..'\r\n'..[[Content-Disposition:form-data;名称=“我的文件”;filename="1.jpg"]]..'\r\n'..[[Content-Type:image/jpeg]]..'\r\n\r\n'local_table1='\r\n'..[[--abcd]]..'\r\n'..[[内容配置:表单数据;name="type";]]..'\r\n\r\n'..[[0]]local_table2='\r\n'..[[--abcd]]..'\r\n'..[[内容配置:表单数据;name="themeName";]]..'\r\n\r\n'..[[1482753000731]]local_end='\r\n'..[[--abcd--]]..'\r\n'localreqfile=io.open(your-file-path)localfile_attr=lfs.attributes(your-file-path)localsize=file_attr.sizelocalbody,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格式数据并发送请求谢谢阅读。
