multipart/form-data


一.什么是multipart/form-data

首先我們需要明白在html中的enctype屬性.
enctype:規定了form表單在發送到服務器時候編碼方式。有如下的三個值。
application/x-www-form-urlencoded。默認的編碼方式。但是在用文本的傳輸和MP3等大型文件的時候,使用這種編碼就顯得 效率低下。
multipart/form-data 。 指定傳輸數據為二進制類型,比如圖片、mp3、文件。
text/plain。純文體的傳輸。空格轉換為 “+” 加號,但不對特殊字符編碼。

二.明確在enctype參數為application/x-www-form-urlencoded的時候post和get請求參數和請求體是什么形式的

2.1 get請求

請求頭:

GET/www.xxx.com?name=%22hello+world%22&**file=temp.png**&submit=submit HTTP/1.1

因為get請求沒有請求體,所有他的所有參數都是在url的后邊添加。type=file的表單項只能獲取到文件的名字,並不能獲取文件的內容。

2.2 post請求

請求頭:

POST /www.baidu.com HTTP/1.1

請求體:

name=%22hello+world%22&file=temp.png&submit=submit

(1)我們可以發現不管是post請求和get請求,他們的參數存在的形式都是不變的,通過key=value的形式存在。
(2)表單項type=filed只能獲取獲取文件的名字不能獲取文件的內容。

三. multipart/form-data

...
Content-Type: multipart/form-data; boundary=${boundary}

--${boundary}
...
...

--${boundary}--

請求內容格式為Content-Type: multipart/form-data,用來指定請求內容的數據編碼格式。

3.1 boundary字符串

該格式會生成一個boundary字符串來分割請求頭與請求體的,具體的是以一個boundary=${boundary}來進行分割。

1、上面boundary=${boundary}之后就是請求體內容了,
2、請求體內容各字段之間以--${boundary}來進行分割,
3、以--${boundary}--來結束請求體內容。

3.2 get請求 無效

請求頭:

GET/www.xxx.com?name=%22hello+world%22&file=temp.png&submit=submit HTTP/1.1

get請求和multipart/form-data結合無效,因為文件上傳需要請求體

3.3 post請求:

請求頭:

POST /www.xxx.com HTTP/1.1

請求體:

------WebKitFormBoundaryIZDrYHwuf2VJdpHw
Content-Disposition: form-data; name="name"

"hello world"
------WebKitFormBoundaryIZDrYHwuf2VJdpHw
Content-Disposition: form-data; name="file"; filename="temp.png"
Content-Type: image/png

.PNG
.
...
IHDR...
..........Y../..,+|.$aIk.v...G?...P.P,,...m..e.2....v.7.	pHYs...%...%.IR$....|IDAT(.cTT....................:.?.......}.(.Pd`A..V...L...?..#.....4.o..LS.....W.d.?...A8..LS...(.u.......D.b......b.....o&..;..<.1......IEND.B`.
------WebKitFormBoundaryIZDrYHwuf2VJdpHw
Content-Disposition: form-data; name="submit"

submit
------WebKitFormBoundaryIZDrYHwuf2VJdpHw--

3.4 多部件請求體

通過觀察發現這個的請求體就發生了變化。這種請求體被稱之為多部件請求體
什么是多部件請求體:就是把每一個表單項分割為一個部件。
因為表單項分為普通表單項文件表單項,所以說部件也有區別。

3.4.1 普通表單項:

  • 一個請求頭:Content-Disposition: form-data; name=”name”
  • 一個請求體:里面就是我們表單的值”hello world”

3.4.2 文件表單項:

  • 兩個請求頭:
    • Content-Disposition: form-data; name="file";
    • filename="temp.png"
  • 一個請求體:
.PNG
.
...
IHDR...
..........Y../..,+|.$aIk.v...G?...P.P,,...m..e.2....v.7.	pHYs...%...%.IR$....|IDAT(.cTT....................:.?.......}.(.Pd`A..V...L...?..#.....4.o..LS.....W.d.?...A8..LS...(.u.......D.b......b.....o&..;..<.1......IEND.B`.
------WebKitFormBoundaryIZDrYHwuf2VJdpHw
Content-Disposition: form-data; name="submit"

submit
------WebKitFormBoundaryIZDrYHwuf2VJdpHw--

3.5 FormData對象

XMLHttpRequest Level 2添加了一個新的接口FormData。利用FormData對象,我們可以通過JavaScript用一些鍵值對來模擬一系列表單控件,我們還可以使用XMLHttpRequest的send()方法來異步的提交這個"表單"。

var formData = new FormData();
formData.append("username", "Groucho");
formData.append("accountnum", 123456);
fetch('/users', {
  method: 'POST',
  body: formData
})

上面創建了一個FormData對象,通過fetch進行ajax請求時,會自動為其將其轉為form-data格式,無需手動添加格式。

3.6 對象轉FormData對象

對於FormDat對象,像上面那種形式可以直接添加參數比較方便,但是對於對象或者嵌套對象:

 let userObj = {userName: ’xxx', age: '21'};
 formData.append('user', userObj);

上面形式添加formData參數user,並不會獲取到其真正的內容,而是返回userObj的Object.prototype.toString.call(userObj)的值作為user字段的值。

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

[object Object]

遺憾的是,FormData對象沒有像JSON.stringify那樣的方法能批量將對象形式轉換為對應的形式,formData而言是將對象的key轉換為正確formData請求參數字段名,例如如下對象:

var obj = {
    a: '2',
    b: {c: 'test'},
    c: [
        {id: 1, name: 'xx'},
        {id:2 ,name: 'yy', info: {d: 4} }
    ]
}

這樣轉換為FormData對象時,其對應的key應該是下面這樣的:

a: 2
b[c]: test
c[][id]: 1
c[][name]: xx
c[][id]: 2
c[][name]: yy
c[][info][d]:4

這樣,就需要我們自己手動來實現一個轉換數據函數,具體代碼如下:

function objectToFormData (obj, form, namespace) {
  const fd = form || new FormData();
  let formKey;

  for(var property in obj) {
      if(obj.hasOwnProperty(property)) {
        let key = Array.isArray(obj) ? '[]' : `[${property}]`;
        if(namespace) {
          formKey = namespace + key;
        } else {
          formKey = property;
        }

        // if the property is an object, but not a File, use recursivity.
        if(typeof obj[property] === 'object' && !(obj[property] instanceof File)) {
          objectToFormData(obj[property], fd, formKey);
        } else {

          // if it's a string or a File object
          fd.append(formKey, obj[property]);
        }

      }
    }

  return fd;

}

這樣,就可以將對象轉化為對應的formData的格式了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM