# 閱讀技術文章_檔案上傳邏輯(1) ---- ###### tags: `檔案上傳` `技術文章` `javascript` `jQuery` `Ajax` `PHP` 文章內所有成就皆不在我!感謝所有願意分享知識的人 ---- [你真的知道网页上传文件背后的原理吗?](https://mp.weixin.qq.com/s/C3H6eNmfBmdX7urHS5dLwA) ## 目錄 - MIME > - MIME類型結構內容 > - Type - Content Type - multipart/form-data - multipart/form-data 結構 - 消息体 - 檔案上傳流程PPT - 補充 引用 >想以代码的方式上傳文件API,要怎麼做? 也非常简单,很多开发语言有很多现成函式的庫,比如PHP通过Curl庫上傳文件非常容易。再深入想一想,如果不使用这些庫,怎么上傳文件?可能会难倒很多人,所以这篇文章简单讲讲文件上傳的原理,其实就是根据HTTP协议的定义,封装一个HTTP消息体。 消息體後面會解釋 --- ## MIME 多用途網際網路郵件擴展(英語:Multipurpose Internet Mail Extensions,縮寫:MIME)是一個網際網路標準,它擴展了電子郵件標準,使其能夠支持: - 非ASCII字符文本 - 非文本格式附件(二進位、聲音、圖像等) - 由多部分(multiple parts)組成的消息體 - 包含非ASCII字符的頭信息(Header information)。這個標準被定義在 RFC 2045、RFC 2046、RFC 2047、RFC 2048、RFC 2049 等RFC中。 MIME改善了由 RFC 822 轉變而來的 RFC 2822 ,這些舊標準規定電子郵件標準並不允許在郵件消息中使用7位ASCII字符集以外的字符。正因如此,一些非英語字符消息和二進位文件,圖像,聲音等非文字消息原本都不能在電子郵件中傳輸(MIME可以)。 >MIME規定了用於表示各種各樣的數據類型的符號化方法。此外,在全球資訊網中使用的HTTP協議中也使用了MIME的框架,標準被擴展為網際網路媒體類型。 MIME不是HTTP協議的一部分,就像我们每個人都是獨一無二的,有自己的屬性,互联网上每個资源也有屬性,比如有些资源是图片,有些是影片,有些是HTML页面,MIME规定了每种资源的類型,这個類型不是随便定义的,由IANA负责登记和维护。 比如你看到一個URL地址,`http://localhost/image.png`,我们其实并不是通过.png 後綴判断資源類型的,而是通过MIME来獲知该資源類型的,这个图片的MIME可能就是image/png(至于客户端如何知晓資源的MIME类型,後面會講),现在是不是有了點感性的認知了。 MIME,从它的英文全稱来看,它和mail有关系,是由mail应用定義而来的,一封郵件由多种資源组成,為了將不同類型的資源组成在邮件中,MIME產生了。隨著網際網路Web的發展,MIME的作用越来越多,擴展也越来越多,MIME概念也逐步移到了Web。 ## MIME類型結構內容 內容類型(Content-Type),這個頭部領域用於指定消息的類型。一般以下面的形式出現。 ``` Content-Type: [type]/[subtype]; parameter ``` type相当于某些類型的集合,而subtype相当于子類型。以image/png为例,image表示图片類型集合,png表示某种類型图片。 ## Type - Text:用於標準化地表示的文本信息,文本消息可以是多種字符集和或者多種格式的; - Multipart:用於連接消息體的多個部分構成一個消息,這些部分可以是不同類型的數據; - Application:用於傳輸應用程式數據或者二進位數據; - Message:用於包裝一個E-mail消息; - Image:用於傳輸靜態圖片數據; - Audio:用於傳輸音頻或者音聲數據; - Video:用於傳輸動態影像數據,可以是與音頻編輯在一起的視頻數據格式。 subtype用於指定Type的詳細形式。 content-type/subtype配對的集合和與此相關的參數 - text/plain(純文本) - text/html(HTML文檔) - application/xhtml+xml(XHTML文檔) - multipart/alternative(HTML郵件的HTML形式和純文本形式,相同內容使用不同形式表示) - application/x-www-form-urlencoded(使用HTTP的POST方法提交的表單) - multipart/form-data(同上,但主要用於表單提交時伴隨文件上傳的場合) >application/x-www-form-urlencoded(使用HTTP的POST方法提交的表單) multipart/form-data(同上,但主要用於表單提交時伴隨文件上傳的場合) 其实本篇文章的主角就是multipart/form-data ## Content Type 客戶端如何知曉每種資源的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標籤: ```htmlembedded= <form action="upload.php" method="post" enctype="multipart/form-data"> Select image to upload: <input type="file" name="fileToUpload" id="fileToUpload"> <input type="submit" value="Upload Image" name="submit"> </form> ``` 关于HTML表单上传可以参考 https://www.w3.org/TR/html5/sec-forms.html#multipart-form-data 或 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頭用途也很廣泛,在本文就不重点描述了。 其实要自行封装文件上传,最好的办法就是用自己熟悉的開發语言實現一下,这样印象才更深刻,希望这篇文章对你有用。 ## 檔案上傳流程PPT      ## 補充 作者: 虞大胆的叽叽喳喳 《深入浅出HTTPS:从原理到实战》,本书github地址是 https://github.com/ywdblog/httpsbook,大家可以一起讨论本书。 本书豆瓣地址 https://book.douban.com/subject/30250772/ ## 參考資料 [多用途網際網路郵件擴展_wiki](https://zh.wikipedia.org/wiki/%E5%A4%9A%E7%94%A8%E9%80%94%E4%BA%92%E8%81%AF%E7%B6%B2%E9%83%B5%E4%BB%B6%E6%93%B4%E5%B1%95)
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up