FormData 和 Content-Type: multipart/form-data

1、FormData

現代 Web 應用中頻繁使用的一項功能就是表單數據序列化,XMLHttpRequest 2 級爲此定義了 FormData 類型,FormData 爲序列化表單以及建立與表單格式相同的數據(經過 JS 來模擬表單鍵值對)提供了便利。html

let xhr = new XMLHttpRequest()

    xhr.onreadystatechange = function (e) {
      if (xhr.readyState === 4) {
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
          console.log(xhr.responseText)
        } else {
          console.log('Opps~failed~!')
        }
      }
    }
    xhr.open('post', 'https://www.easy-mock.com/mock/59b95cf3e0dc663341a8fa20/example/upload', true)

使用 post 發送表單鍵值對格式的請求時,依然可使用查詢字符串格式,只是要放在請求體中,即傳入send()中,介紹如下幾種方法:chrome

方法1:直接模仿表單提交的形式,缺點是須要手動設置請求頭,還要本身序列化爲查詢字符串的形式傳給 xhr 對象。express

xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
    const queryString = 'name=wangpeng&age=24&someNumberString=19'
    xhr.send(queryString)

方法2:使用 FormData() 構造函數,瀏覽器會自動識別並添加請求頭 "Content-Type: multipart/form-data",且參數依然像是表單提交時的那種鍵值對兒,此外 FormData() 構造函數 new 時能夠直接傳入 form 表單的 dom 節點。後端

const params = new FormData()
    params.append('name', 'tom')
    params.append('age', 24)
    params.append('someNumberString', '18')
    xhr.send(params)

方法3:使用 URLSearchParams() 構造函數傳入查詢字符串,返回的實例和 FormData 類似,同時瀏覽器也作出相同的行爲。瀏覽器

const params = new URLSearchParams()
    params.append('name', 'tom')
    params.append('age', 24)
    params.append('someNumberString', '18')
    xhr.send(params)

另外,URLSearchParams() 構造函數 new 時能夠直接傳入查詢字符串格式的參數,好比:app

const params = new URLSearchParams('name=tom&age=24&someNumberString=19')

可見send()方法很靈活:dom

xhr.send("foo=bar&lorem=ipsum"); 
// xhr.send('string'); 
// xhr.send(new Blob()); 
// xhr.send(new Int8Array()); 
// xhr.send({ form: 'data' }); 
// xhr.send(document);

2、multipart/form-data時的HTTP消息文本

第一行是請求行,指明瞭方法、URI 和 HTTP 版本號;
接着是消息頭(簡單起見,只有一個 Conten-Type);
而後空出一行;
接下來就是消息體,能夠看到使用 multipart/form-data 時,消息體經過 boundary 來分隔多個字段,且每一個字段都有本身的頭部,提供了額外的信息。字段的值多是普通的字符,也多是二進制文件:ide

POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryyb1zYhTI38xpQxBK

------WebKitFormBoundaryyb1zYhTI38xpQxBK
Content-Disposition: form-data; name="city_id"

1
------WebKitFormBoundaryyb1zYhTI38xpQxBK
Content-Disposition: form-data; name="company_id"

2
------WebKitFormBoundaryyb1zYhTI38xpQxBK
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png

PNG ... content of chrome.png ...
------WebKitFormBoundaryyb1zYhTI38xpQxBK--

3、multipart/form-data定義源頭

multipart/form-data最初由 《RFC 1867: Form-based File Upload in HTML》文檔定義。函數

Since file-upload is a feature that will benefit many applications, this proposes an
extension to HTML to allow information providers to express file upload requests uniformly, and a MIME compatible representation for file upload responses.post

文檔簡介中說明文件上傳做爲一種常見的需求,在目前(1995年)的html中的form表單格式中還不支持,所以發明了一種兼容此需求的MIME type。

The encoding type application/x-www-form-urlencoded is inefficient for sending large quantities of binary data or text containing non-ASCII characters. Thus, a new media type,multipart/form-data, is proposed as a way of efficiently sending the
values associated with a filled-out form from client to server.

文檔中也寫了爲何要新增一個類型,而不使用舊有的application/x-www-form-urlencoded:由於舊有類型不適合用於傳輸大型二進制數據或者包含非ASCII字符的數據。日常咱們使用這個類型都是把表單數據使用url編碼後傳送給後端,二進制文件固然沒辦法一塊兒編碼進去了。因此multipart/form-data就誕生了,專門用於有效的傳輸文件。


參考:
1. 豆瓣:JavaScript高級程序設計(第3版)
2. MDN: FormData
3. MDN: XMLHttpRequest.send()
4. 爲何上傳文件要使用multipart/form-data
5. 談談form-data請求格式

相關文章
相關標籤/搜索