摘要:再深入想一想,如果不使用这些库,怎么上传文件可能会难倒很多人,所以这篇文章简单讲讲文件上传的原理,其实就是根据协议的定义,封装一个消息体。
今年第三季度工作上完成了一个比较有意思的项目,类似于外包的性质,主要任务就是提供一大堆API,其中一个API是上传附件,完成开发后,对方的程序员问我,这个API怎么调用,当时我就愣住了,因为自己也没想过这个问题,一般情况下,我就是用 Curl 命令行或 Postman 测试API的。
针对文件上传,我使用 Curl 测试,比如:
# 使用@引用一个文件
$ curl -F"param=value" -F"file=@/path/file.png" http://localhost/api.php
如果使用Postman测试,如下图:
注意观察form-data和File标签。
看上去是不是很简单,现在换个角度,你想以代码的方式上传文件API,怎么办?也非常简单,很多开发语言有很多现成的库,比如PHP通过Curl库上传文件非常容易。再深入想一想,如果不使用这些库,怎么上传文件?可能会难倒很多人,所以这篇文章简单讲讲文件上传的原理,其实就是根据HTTP协议的定义,封装一个HTTP消息体。
MIME
首先必须先讲下MIME(Multipurpose Internet Mail Extensions),它并不是HTTP协议的一部分,就像我们每个人都是独一无二的,有自己的属性,互联网上每个资源也有属性,比如有些资源是图片,有些是视频,有些是HTML页面,MIME规定了每种资源的类型,这个类型不是随便定义的,由IANA负责登记和维护。
说的有点难理解,比如你看到一个URL地址,http://localhost/image.png,我们其实并不是通过.png后缀判断资源类型的,而是通过MIME来获知该资源类型的,这个图片的MIME可能就是image/png(至于客户端如何知晓资源的MIME类型,后面会讲),现在是不是有了点感性的认识了。
MIME类型结构如下:
type/subtype
type相当于某些类型的集合,而subtype相当于子类型。以image/png为例,image表示图片类型集合,png表示某种类型图片。
让我们看几个比较重要的MIME类型:
text/plain text/html application/octet-stream multipart/form-data
其实本篇文章的主角就是multipart/form-data,再等一等,先别着急,再一次说说MIME,从它的英文全称来看,它和mail有关系,是由mail应用定义而来的,一封邮件由多种资源组成,为了将不同类型的资源组成在邮件中,MIME产生了。随着互联网Web的发展,MIME的作用越来越多,扩展也越来越多,MIME概念也逐步移到了Web。
Content Type
现在我们定义了每种资源的MIME类型,那么客户端如何知晓每种资源的MIME类型呢?这时候就要使用Content-Type HTTP Header 头了,比如我们请求一个资源,Web服务器在发送资源的时候,发送了“content-type:image/png” Header 头,这样客户端就知道该资源是一个png图片了。
如果客户端发送了一个 “Content-Type: multipart/form-data;”,代表客户端要上传一个附件。
也就是说 Content-Type 后面的值就是一个 MIME 类型,聪明的同学也猜到了,上传附件和 multipart/form-data MIME 类型有关,确实是!
multipart/form-data
multipart/form-data 这个MIME类型并不是标准的MIME类型,而是因为Web的需要扩展而来的,我们在开发网页的时候为了上传一个文件,会输入以下的HTML标签:
关于HTML表单上传可以参考 https://www.w3.org/TR/html5/s... 或 RFC 1867(Form-based File Upload in HTML,该RFC已经废弃了)。
那么multipart/form-data表示什么呢?multipart互联网上的混合资源,就是资源由多种元素组成,form-data表示可以使用HTML Forms 和 POST 方法上传文件,具体的定义可以参考RFC 7578。
multipart/form-data结构
说了那么多,从HTTP协议的角度,最后看下文件上传的HTTP消息体,使用Postman也容易看出,如下:
POST /api.php HTTP/1.1 Host: localhst Cache-Control: no-cache Content-Type: multipart/form-data; boundary=----FormBoundary ------FormBoundary Content-Disposition: form-data; name="file"; filename="file.png" Content-Type: image/png <图片二进制内容> ------FormBoundary Content-Disposition: form-data; name="param1" value1 ------FormBoundary Content-Disposition: form-data; name="param2" value2 ------FormBoundary--
消息体什么意思呢,如果你自行想使用代码实现文件上传,要根据定义自行封装HTTP消息,接下去我们简单描述一下。
Content-Type: multipart/form-data; boundary=——FormBoundary 表示要上传附件,其中boundary表示分隔符,如果要上传多个表单项,就要使用boundary分割,每个表单项由———FormBoundary开始,以———FormBoundary结尾。每一个表单项又由Content-Type和Content-Disposition组成。
------FormBoundary Content-Disposition: form-data; name="param1" value1 ------FormBoundary
表示普通的一个表单元素,最重要的是理解 Content-Disposition HTTP 消息头,其中第一个参数总是固定不变的form-data,name表示表单元素属性名,回车换行符后面的内容就是元素的值。
接下去重点描述和文件有关的:
------FormBoundary Content-Disposition: form-data; name="file"; filename="file.png" Content-Type: image/png
<图片二进制内容>
------FormBoundary
其中多了一个filename参数,表示文件名,Content-Type 告诉服务器这是一个图片,内容就是图片的二进制数据。
其实Content-Disposition这个HTTP header头用途也很广泛,在本文就不重点描述了。
其实要自行封装文件上传,最好的办法就是用自己熟悉的开发语言实现一下,这样印象才更深刻,希望这篇文章对你有用。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/53571.html
摘要:当用户完成选择文件动作时,提交子页面中的。从此我们上传文件就欢欣鼓舞的来找了。因为的核心是对象,异步的实现是通过一个对象,一般简称该对象对。这些回答基于自己理解,如有不妥,希望路过的大神轻喷,指正。 背景 平时工作中经常会遇到需要上传文件的情况,如果你用ant design 或者element ,它们都提供了上传的组件。 我们分别来看一下element 和 antd 手动上传怎么处理:...
摘要:欢迎来我的个人站点性能优化其他优化浏览器关键渲染路径开启性能优化之旅高性能滚动及页面渲染优化理论写法对压缩率的影响唯快不破应用的个优化步骤进阶鹅厂大神用直出实现网页瞬开缓存网页性能管理详解写给后端程序员的缓存原理介绍年底补课缓存机制优化动 欢迎来我的个人站点 性能优化 其他 优化浏览器关键渲染路径 - 开启性能优化之旅 高性能滚动 scroll 及页面渲染优化 理论 | HTML写法...
阅读 3044·2021-09-24 10:26
阅读 3148·2021-09-23 11:54
阅读 4566·2021-09-22 15:33
阅读 2219·2021-09-09 09:33
阅读 1618·2021-09-07 10:10
阅读 932·2019-08-30 11:09
阅读 2790·2019-08-29 17:13
阅读 974·2019-08-29 12:35