http:文件上传背后发生了什么?

发布于 2022-09-04 19:01:12 字数 885 浏览 21 评论 0

我虽然知道,文件上传的一般过程,即在页面表单中加入属性: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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

彩虹直至黑白 2022-09-11 19:01:12

话说PHP里面确实是语言层面已经都做好了你没法看,但是node.js里面你可以直接看源代码的呀:

比如 busboylib/types/multipart.js
,又如 formidablelib/multipart_parser.js

而上传文件的协议标准上面已经有人说了,见 RFC 7578

☆獨立☆ 2022-09-11 19:01:12

自己试着写了一下。大概的流程是:
1、接收header,以\r\n结束。
大概这个样子:

POST / HTTP/1.1
Host: xxx.com
Connection: keep-alive
Content-Length: 34360
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary9JYnHmp5Rtqoc1iQ
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8

2、检查Http Method,如果是POST,就获取Content-Length头的值,如果存在这个头且不为0,那就准备接收Body,直到接收到Content-Length长度的内容,则认为请求接收完成。

3、到上一步,我们拿到了body,现在我们要判断body内容类型,我们获取Content-Type头,如果是Content-Type: application/x-www-form-urlencoded 那直接用&分割,再用=分割就得到表单数据了。像这个样子:

_token=JHjUoYi5R9jgU1ZFgsQYOvEpTx02dSGhqW4pWbNrKaT&email=nnn%40xxx.com&password=xxx&login=1

如果是Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryRazVhL46T6okNz7W,那就是表示我们收到的是一个二进制数据。并使用boundary的值来作为边界字符串(用来分割多个块)
(这里需要说一下,headers并不是一个key-value数组,而是一个key-array, 很多HTTP协议实现里,getHeader方法都是返回数组,而不是一个字符串)

二进制的body大概是这个样子

------WebKitFormBoundary9JYnHmp5Rtqoc1iQ
Content-Disposition: form-data; name="file"; filename="A.jpg"
Content-Type: image/jpeg
{binary}

------WebKitFormBoundary9JYnHmp5Rtqoc1iQ--

其中的{binary}就是图片文件的二进制所在的地方。至此,我们就能从请求里面得到上传文件了。

斜体文字实际操作过程中,还有一些小坑,例如,客户端在POST上传超过1KB数据时,会在Headers里面有一个Expect: 100-continue如果服务端收到这个header,必须给客户端发送HTTP/1.1 100 Continue\r\n\r\n,客户端才会继续发送body数据。

热血少△年 2022-09-11 19:01:12

其实不用管HTTP,它就是个送快递的。 FORM里enctype=multipart/form-data意思就是表单是文件流,打包封箱传到服务器,服务器端再将文件流拆箱还原成文件。

可以忽略网络的存在。你随便用个语言做一个从本地读取一个文件,其实工作过程一样的。打开目标文件,读取文件流,把文件流写到另外一个文件,关闭流。

查看相关语言的文件流操作即可。没啥高深的,一般都是封装好的。底层一点也不过就是把文件以特定格式读到数组各种拼接。

也许没回答到点子上,就当帮顶吧 :D

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文