在Spa單頁面橫行的時代,前后端交互基本都是Json交互(也有通過FormData的,比如上傳文件)。而在之前的Jsp,Php前后不分家的時候,前后交互好大一部分都是通過Form表單來完成的。From標簽個屬性叫 enctype
,這屬性指定了Form的Content-Type,可取的只有application/x-www-form-urlencoded, multipart/form-data, text/plain。
而Content-Type包含3個部分:
- media-type: 資源或數據的 MIME type (必填)
- charset: 字符編碼標准
- boundary: 對於多部分實體,boundary 是必需的,其包括來自一組字符的1到70個字符,已知通過電子郵件網關是非常健壯的,而不是以空白結尾。它用於封裝消息的多個部分的邊界
application/x-www-form-urlencoded 是Form默認的Content-Type:表單提交時編碼必須遵循以下標准:
- key和value都會被編碼。空格被替換為‘+’,保留字編碼對着參照 [RFC1738],非轉義字符被替換為‘’%hh‘’的格式(一個%和兩個代表示ASCII碼的16進制數字),換行被替換為‘%D0%0A’(對應CR LF),都可以通過encodeURI函數轉換,詳細還請查閱 mdn
- key和value用‘=’來分隔,每一對key和value用‘&’來分隔
比如:
multipart/form-data 是用FormData來傳遞數據,和上邊的區別是,FormData用來傳遞大數據(非ascii字符和二進制數據),具體請參考另一篇文章 post使用form-data和x-www-form-urlencoded的本質區別 (這篇博客講的感覺很詳細了),編碼規則如下:
- 包含一個Content-Disposition字段,值為form-data
- 一個name屬行,值為對應表單key的name字段
- 所有的Mime傳輸一樣,用CR LF(‘%0D%0A’)來分隔數據
比如:划線處為規則3
接下我詳細說下multipart/form-data編碼,假設我們有以下Form
<FORM action="http://server.com/cgi/handle" enctype="multipart/form-data" method="post"> <P> What is your name? <INPUT type="text" name="submit-name"><BR> What files are you sending? <INPUT type="file" name="files"><BR> <INPUT type="submit" value="Send"> <INPUT type="reset"> </FORM>
當用戶輸入‘Larry’在文本input中,還選擇了一個文本文件‘file1.txt’,然后點擊提交按鈕,傳向后台的body體為:
Content-Type: multipart/form-data; boundary=AaB03x
--AaB03x
Content-Disposition: form-data; name="submit-name"
Larry
--AaB03x
Content-Disposition: form-data; name="files"; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--AaB03x--
我們看到藍色部分,就是Content-Type,參考上上邊提到的,少了charset,多了個boundary(我們知道,在application/x-www-form-urlencoded 中是用‘&’來告訴服務器每一個key和value,比如一個get請求: http://localhost:8080/api?name=John&age=12 ,
那么在multipart/form-data我們怎么告訴服務器呢,答案就是boundary,有了這個字段,服務器就知道一個value是從哪里開始和到哪里結束,這個字段開發者是不用寫的,瀏覽器會自動加上,網上說我們也可以自行設置,比如你可以設置你喜歡的字符,但是我沒有成功,每次都是隨機的給分配一個,測試如下:)
回到剛才的Form表單,如果用戶選擇了第二個文件‘file2.gif’,傳輸結構會是以下:
Content-Type: multipart/form-data; boundary=AaB03x
--AaB03x
Content-Disposition: form-data; name="submit-name"
Larry
--AaB03x
Content-Disposition: form-data; name="files"
Content-Type: multipart/mixed; boundary=BbC04y
--BbC04y
Content-Disposition: file; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--BbC04y
Content-Disposition: file; filename="file2.gif"
Content-Type: image/gif
Content-Transfer-Encoding: binary
...contents of file2.gif...
--BbC04y--
--AaB03x--