一、application/x-www-form-urlencoded
1、它是post的默認格式,使用js中encodeURIComponent轉碼方法。包括將name、value中的空格替換為加號;將非ascii字符做百分號編碼;將input的name、value用‘=’連接,不同的input之間用‘&’連接。
2、百分號編碼什么意思呢。比如漢字‘丁’吧,他的utf8編碼在十六進制下是0xE4B881,占3個字節,把它轉成字符串‘E4B881’,變成了六個字節,每兩個字節前加上百分號前綴,得到字符串“%E4%B8%81”,變成九個ascii字符,占九個字節(十六進制下是0x244534254238253831)。把這九個字節拼接到數據包里,這樣就可以傳輸“非ascii字符的 utf8編碼的 十六進制表示的 字符串的 百分號形式”,^_^。
3、同樣使用encodeURIComponent轉碼,這種post格式跟get的區別在於,get把轉換、拼接完的字符串用‘?’直接與表單的action連接作為URL使用,所以請求體里沒有數據;而post把轉換、拼接后的字符串放在了請求體里,不會在瀏覽器的地址欄顯示,因而更安全一些。
二、multipart/form-data
1、對於一段utf8編碼的字節,用application/x-www-form-urlencoded傳輸其中的ascii字符沒有問題,但對於非ascii字符傳輸效率就很低了(漢字‘丁’從三字節變成了九字節),因此在傳很長的字節(如文件)時應用multipart/form-data格式。smtp等協議也使用或借鑒了此格式。
2、此格式表面上發送了什么呢。用此格式發送一段一句話和一個文件,請求體如下

同時請求頭里規定了Content-Type: multipart/form-data; boundary=----WebKitFormBoundarymNhhHqUh0p0gfFa8
可見請求體里不同的input之間用一段叫boundary的字符串分割,每個input都有了自己一個小header,其后空行接着是數據。
3、此格式實際上發送了什么呢。fiddler抓包如下

右邊明顯看到了一段亂碼,為什么呢,以漢字‘丁’為例,其utf8編碼為0xE4B881,這三個字節會直接拼接到數據包中,即其在實際發送時只占三字節,上圖右邊是逐字節轉為ascii字符顯示的,因此會顯示為三個亂碼字符。
4、由上可見,multipart/form-data將表單中的每個input轉為了一個由boundary分割的小格式,沒有轉碼,直接將utf8字節拼接到請求體中,在本地有多少字節實際就發送多少字節,極大提高了效率,適合傳輸長字節。
