http:文件上传背后发生了什么?
我虽然知道,文件上传的一般过程,即在页面表单中加入属性:enctype=multipart/form-data
,然后通过 <input type=file> 来选择文件,即可提交文件到指定服务器。在此过程中,提交的表单会与一般post有所不同,http主体大概是:
Content-Type: multipart/form-data; boundary=---------------------------14579331036932498511351460782
Content-Length: 418
-----------------------------14579331036932498511351460782
Content-Disposition: form-data; name="userfile1"; filename="å¤æ³¨è¯´æ.txt"
Content-Type: text/plain
1.±ê×¢ÒÔiPhone6s ÆÁÄ»³ß´çΪ±ê×¼£»
2.Èç¹ûÐèÒª²»Í¬³ß´çµÄicon£¬ÔÙ¸øÎÒ˵¡£
-----------------------------14579331036932498511351460782
Content-Disposition: form-data; name="hehe"
tewtw
-----------------------------14579331036932498511351460782--
在这里,我想探寻的是,服务器端如何接受数据流,并将数据流作为文件保存起来,也就是说从http的层面来说,如何操作这一切?而我搜索到的资料、博客多是从语言层面来解释,而语言之间多是直接做好了封装,如PHP中的$_FILES,node中多是引用formidable,直接一步到位,而未能解释里面的原理。
不知有大神能否指点一二?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
话说PHP里面确实是语言层面已经都做好了你没法看,但是node.js里面你可以直接看源代码的呀:
比如
busboy
中lib/types/multipart.js
,又如
formidable
中lib/multipart_parser.js
而上传文件的协议标准上面已经有人说了,见 RFC 7578
自己试着写了一下。大概的流程是:
1、接收header,以
\r\n
结束。大概这个样子:
2、检查Http Method,如果是POST,就获取Content-Length头的值,如果存在这个头且不为0,那就准备接收Body,直到接收到Content-Length长度的内容,则认为请求接收完成。
3、到上一步,我们拿到了body,现在我们要判断body内容类型,我们获取Content-Type头,如果是
Content-Type: application/x-www-form-urlencoded
那直接用&分割,再用=分割就得到表单数据了。像这个样子:如果是
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryRazVhL46T6okNz7W
,那就是表示我们收到的是一个二进制数据。并使用boundary的值来作为边界字符串(用来分割多个块)(这里需要说一下,headers并不是一个key-value数组,而是一个key-array, 很多HTTP协议实现里,getHeader方法都是返回数组,而不是一个字符串)
二进制的body大概是这个样子
其中的{binary}就是图片文件的二进制所在的地方。至此,我们就能从请求里面得到上传文件了。
斜体文字实际操作过程中,还有一些小坑,例如,客户端在POST上传超过1KB数据时,会在Headers里面有一个
Expect: 100-continue
如果服务端收到这个header,必须给客户端发送HTTP/1.1 100 Continue\r\n\r\n
,客户端才会继续发送body数据。其实不用管HTTP,它就是个送快递的。 FORM里enctype=multipart/form-data意思就是表单是文件流,打包封箱传到服务器,服务器端再将文件流拆箱还原成文件。
可以忽略网络的存在。你随便用个语言做一个从本地读取一个文件,其实工作过程一样的。打开目标文件,读取文件流,把文件流写到另外一个文件,关闭流。
查看相关语言的文件流操作即可。没啥高深的,一般都是封装好的。底层一点也不过就是把文件以特定格式读到数组各种拼接。
也许没回答到点子上,就当帮顶吧 :D