默認狀況下是 application/x-www-urlencoded
,當表單使用 POST 請求時,數據會被以 x-www-urlencoded 方式編碼到 Body 中來傳送,
而若是 GET 請求,則是附在 url 連接後面來發送。html
GET 請求只支持 ASCII 字符集,所以,若是咱們要發送更大字符集的內容,咱們應使用 POST 請求。git
若是要發送大量的二進制數據(non-ASCII),"application/x-www-form-urlencoded"
顯然是低效的,由於它須要用 3 個字符來表示一個 non-ASCII 的字符。所以,這種狀況下,應該使用 "multipart/form-data"
格式。編程
The content type "application/x-www-form-urlencoded" is inefficient for sending large quantities of binary data or text containing non-ASCII characters. The content type "multipart/form-data" should be used for submitting forms that contain files, non-ASCII data, and binary data.瀏覽器
咱們在經過 HTTP 向服務器發送 POST 請求提交數據,都是經過 form 表單形式提交的,代碼以下:服務器
<FORM method="post" action="http://w.sohu.com" > <INPUT type="text" name="txt1"> <INPUT type="text" name="txt2"> </FORM>
提交時會向服務器端發出這樣的數據(已經去除部分不相關的頭信息),數據以下:session
POST / HTTP/1.1 Content-Type:application/x-www-form-urlencoded Accept-Encoding: gzip, deflate Host: w.sohu.com Content-Length: 21 Connection: Keep-Alive Cache-Control: no-cache txt1=hello&txt2=world
對於普通的 HTML Form POST請求,它會在頭信息裏使用 Content-Length
註明內容長度。
請求頭信息每行一條,空行以後即是 Body,即「內容」(entity)。內容的格式是在頭信息中的 Content-Type 指定的,如上是 application/x-www-form-urlencoded
,這意味着消息內容會通過 URL 格式編碼,就像在 GET請 求時 URL 裏的 QueryString 那樣。txt1=hello&txt2=world
app
multipart/form-data
定義在 rfc2388 中,最先的 HTTP POST 是不支持文件上傳的,給編程開發帶來不少問題。可是在1995年,ietf 出臺了 rfc1867,也就是《RFC 1867 -Form-based File Upload in HTML》,用以支持文件上傳。因此 Content-Type 的類型擴充了multipart/form-data 用以支持向服務器發送二進制數據。所以,發送 POST 請求時候,表單 <form> 屬性 enctype 共有二個值可選,這個屬性管理的是表單的 MIME 編碼:curl
① application/x-www-form-urlencoded (默認值)
② multipart/form-datagitlab
注:form 表單中 enctype 的默認值是 enctype="application/x- www-form-urlencoded"
.post
經過 form 表單提交文件操做以下:
<FORM method="POST" action="http://w.sohu.com/t2/upload.do" enctype="multipart/form-data"> <INPUT type="text" name="city" value="Santa colo"> <INPUT type="text" name="desc"> <INPUT type="file" name="pic"> </FORM>
瀏覽器將會發送如下數據:
POST /t2/upload.do HTTP/1.1 User-Agent: SOHUWapRebot Accept-Language: zh-cn,zh;q=0.5 Accept-Charset: GBK,utf-8;q=0.7,*;q=0.7 Connection: keep-alive Content-Length: 60408 Content-Type:multipart/form-data; boundary=ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC Host: w.sohu.com --ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC Content-Disposition: form-data; name="city" Santa colo --ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC Content-Disposition: form-data;name="desc" Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... --ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC Content-Disposition: form-data;name="pic"; filename="photo.jpg" Content-Type: application/octet-stream Content-Transfer-Encoding: binary ... binary data of the jpg ... --ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC--
從上面的 multipart/form-data
格式發送的請求的樣式來看,它包含了多個 Parts,每一個 Part 都包含頭信息部分,
Part 頭信息中必須包含一個 Content-Disposition
頭,其餘的頭信息則爲可選項, 好比 Content-Type
等。
Content-Disposition
包含了 type 和 一個名字爲 name 的 parameter,type 是 form-data,name 參數的值則爲表單控件(也即 field)的名字,若是是文件,那麼還有一個 filename 參數,值就是文件名。
好比:
Content-Disposition: form-data; name="user"; filename="hello.txt"
上面的 "user" 就是表單中的控件的名字,後面的參數 filename 則是點選的文件名。
對於可選的 Content-Type(若是沒有的話),默認就是 text/plain
。
注意:
若是文件內容是經過填充表單來得到,那麼上傳的時候,Content-Type 會被自動設置(識別)成相應的格式,若是無法識別,那麼就會被設置成 "application/octet-stream"
若是多個文件被填充成單個表單項,那麼它們的請求格式則會是 multipart/mixed。
若是 Part 的內容跟默認的 encoding 方式不一樣,那麼會有一個 "content-transfer-encoding"
頭信息來指定。
下面,咱們填充兩個文件到一個表單項中,行程的請求信息以下:
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--
每一個部分使用 --boundary
分割開來,最後一行使用 --boundary--
結尾。
To see exactly what is happening, use nc -l and an user agent like a browser or cURL.
Save the form to an .html file:
<FORM action="http://localhost:8000" method="post" enctype="multipart/form-data"> <p><INPUT type="text" name="text" value="text default"> <p><INPUT type="file" name="file1"> <p><INPUT type="file" name="file2"> <p><BUTTON type="submit">Submit</BUTTON> </FORM>
Create files to upload:
echo 'Content of a.txt.' > a.txt echo '<!DOCTYPE html><title>Content of a.html.</title>' > a.html
Run:
nc -l localhost 8000
Open the HTML on your browser, select the files and click on submit and check the terminal.
nc prints the request received. Firefox sent:
POST / HTTP/1.1 Host: localhost:8000 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:29.0) Gecko/20100101 Firefox/29.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Cookie: __atuvc=34%7C7; permanent=0; _gitlab_session=226ad8a0be43681acf38c2fab9497240; __profilin=p%3Dt; request_method=GET Connection: keep-alive Content-Type: multipart/form-data; boundary=---------------------------9051914041544843365972754266 Content-Length: 554 -----------------------------9051914041544843365972754266 Content-Disposition: form-data; name="text" text default -----------------------------9051914041544843365972754266 Content-Disposition: form-data; name="file1"; filename="a.txt" Content-Type: text/plain Content of a.txt. -----------------------------9051914041544843365972754266 Content-Disposition: form-data; name="file2"; filename="a.html" Content-Type: text/html <!DOCTYPE html><title>Content of a.html.</title> -----------------------------9051914041544843365972754266--
Aternativelly, cURL should send the same POST request as your a browser form:
nc -l localhost 8000 curl -F "text=default" -F "file1=@a.html" -F "file1=@a.txt" localhost:8000
You can do multiple tests with:
while true; do printf '' | nc -l localhost 8000; done
https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4
https://stackoverflow.com/questions/4526273/what-does-enctype-multipart-form-data-mean/28380690#28380690
https://tools.ietf.org/html/rfc2388
https://stackoverflow.com/questions/913626/what-should-a-multipart-http-request-with-multiple-files-look-like