当前位置: 首页 > Web前端 > HTML

网页上传文件原理详解

时间:2023-04-02 13:44:19 HTML

今年第三季度完成了一个有趣的项目,类似外包的性质。主要任务是提供很多API,其中之一就是上传附件。开发完成后,对方A程序员问我这个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(MultipurposeInternetMailExtensions),它并不是HTTP协议的一部分,就像我们每个人都是独一无二的,有自己的属性一样。Internet上的每个资源也都有属性。比如有的资源是图片,有的是视频,有的是HTML页面,MIME指定了每一种资源的类型。这个类型不是随便定义的,是由IANA注册维护的。有点难懂。比如你看到一个URL地址,http://localhost/image.png,我们不是通过.png后缀来判断资源类型,而是通过MIME来学习资源类型。这个图片的MIME可能是image/png(至于client是怎么知道资源的MIME类型的,后面会讲到),大家现在有没有感性的认识呢?MIME类型结构如下:type/subtypetype相当于某些类型的集合,subtype相当于一个子类型。以image/png为例,image代表图片类型的集合,png代表某一类图片。再来看几个比较重要的MIME类型:text/plaintext/htmlapplication/octet-streammultipart/form-data其实本文的主角是multipart/form-data,等一下,别着急,说说再次,MIME,从它的英文全称来看,与邮件有关,由邮件应用程序定义。一封电子邮件由多个资源组成。为了在电子邮件中组合不同类型的资源,创建了MIME。随着InternetWeb的发展,MIME的功能越来越多,扩展也越来越多,MIME的概念也逐渐走向了Web。ContentType既然我们定义了每个资源的MIME类型,那么客户端如何知道每个资源的MIME类型呢?这个时候就用到了Content-TypeHTTPHeader。比如我们请求一个资源,web服务器在发送资源的时候会发送“content-type:image/png”Header,这样客户端就知道这个资源是一个png图片。如果客户端发送“Content-Type:multipart/form-data;”,则表示客户端要上传附件。也就是说Content-Type后面的值是一个MIME类型。聪明的同学也猜到了,上传附件与multipart/form-dataMIME类型有关,确实如此!multipart/form-datamultipart/form-data这种MIME类型并不是标准的MIME类型,而是因为Web的需要而扩展的。当我们开发网页时,为了上传文件,我们会输入如下HTML标签:选择图片上传:HTML表单上传请参考https://www.w3.org/TR/html5/s...或RFC1867(HTML中基于表单的文件上传,此RFC已被废弃)。那么multipart/form-data是什么意思呢?多部分互联网上的混合资源意味着该资源由多个元素组成。form-data表示可以使用HTML表单和POST方法上传文件。具体定义请参考RFC7578。multipart/form-data结构说了这么多。从HTTP协议的角度,最后看一下文件上传的HTTP报文体。使用Postman很容易看到,如下:POST/api.phpHTTP/1.1Host:localhstCache-Control:no-cacheContent-Type:multipart/form-data;boundary=----FormBoundary------FormBoundaryContent-Disposition:form-data;名称=“文件”;filename="file.png"Content-Type:image/png<图片二进制内容>------FormBoundaryContent-Disposition:form-data;name="param1"value1------FormBoundaryContent-Disposition:form-data;name="param2"value2------FormBoundary--消息体是什么意思?如果要使用代码上传文件,需要根据定义自行封装HTTP报文。接下来我们简单描述一下。内容类型:多部分/表单数据;boundary=——FormBoundary表示要上传附件,其中boundary代表分隔符,如果要上传多个表单项,则必须以boundary分隔,每个表单项以——FormBoundary开头,以——结尾-形式边界。每个表单项由Content-Type和Content-Disposition组成。------FormBoundaryContent-Disposition:表单数据;name="param1"value1------FormBoundary代表一个普通的表单元素,最重要的是理解Content-DispositionHTTP消息头,其中第一个参数永远是固定的form-data,name代表表单元素的属性名,回车换行后的内容为元素的值。接下来重点关注文件相关的描述:------FormBoundaryContent-Disposition:form-data;名称=“文件”;filename="file.png"Content-Type:image/png<图片二进制内容>------FormBoundary有一个filename参数,表示文件名,Content-Type告诉服务器这是一张图片,和内容是图片的二进制数据。实际上,HTTPheaderContent-Disposition的用途非常广泛,本文不做重点介绍。其实自己打包上传文件最好的方式就是用自己熟悉的开发语言来实现,这样印象会更深。我希望这篇文章对你有用。