from屬性EncType提交數(shù)據(jù)的格式詳解—在angular中的應用
我們知道,HTTP 協(xié)議是以 ASCII 碼傳輸渣刷,建立在 TCP/IP 協(xié)議之上的應用層規(guī)范。規(guī)范把 HTTP 請求分為三個部分:狀態(tài)行、請求頭、消息主體汰具。類似于下面這樣:
轉(zhuǎn)載請注明出處:http://www.zhoulujun.cn/zhoulujun/html/webfront/SGML/web/2017_0719_8034.html
協(xié)議規(guī)定 POST 提交的數(shù)據(jù)必須放在消息主體(entity-body)中,但協(xié)議并沒有規(guī)定數(shù)據(jù)必須使用什么編碼方式菱魔。實際上留荔,開發(fā)者完全可以自己決定消息主體的格式,只要最后發(fā)送的 HTTP 請求滿足上面的格式就可以澜倦。
但是存谎,數(shù)據(jù)發(fā)送出去,還要服務端解析成功才有意義肥隆。一般服務端語言如 php既荚、python 等,以及它們的 framework栋艳,都內(nèi)置了自動解析常見數(shù)據(jù)格式的功能恰聘。服務端通常是根據(jù)請求頭(headers)中的 Content-Type 字段來獲知請求中的消息主體是用何種方式編碼,再對主體進行解析吸占。所以說到 POST 提交數(shù)據(jù)方案晴叨,包含了 Content-Type 和消息主體編碼方式兩部分。
我們悉知矾屯,form表單屬性EncType表明提交數(shù)據(jù)的格式
用 Enctype 屬性指定將數(shù)據(jù)回發(fā)到服務器時瀏覽器使用的編碼類型兼蕊。
下邊是說明:
application/x-www-form-urlencoded: 窗體數(shù)據(jù)被編碼為名稱/值對。這是標準的編碼格式件蚕。一般默認為application/x-www-form-urlencoded孙技。
multipart/form-data: 窗體數(shù)據(jù)被編碼為一條消息,頁上的每個控件對應消息中的一個部分排作。
text/plain: 窗體數(shù)據(jù)以純文本形式進行編碼牵啦,其中不含任何控件或格式字符。
當action為get時候妄痪,瀏覽器用x-www-form-urlencoded的編碼方式把form數(shù)據(jù)轉(zhuǎn)換成一個字串(name1=value1&name2=value2...)哈雏,然后把這個字串a(chǎn)ppend到url后面,用?分割衫生,加載這個新的url裳瘪。
當action為post時候,瀏覽器把form數(shù)據(jù)封裝到http body中罪针,然后發(fā)送到server彭羹。
如果沒有type=file的控件,用默認的application/x-www-form-urlencoded就可以了站故。
但是如果有type=file的話皆怕,就要用到multipart/form-data了。瀏覽器會把整個表單以控件為單位分割西篓,并為每個部分加上Content-Disposition(form-data或者file),Content-Type(默認為text/plain),name(控件name)等信息愈腾,并加上分割符(boundary)
在Form元素的語法中,EncType表明提交數(shù)據(jù)的格式 用 Enctype 屬性指定將數(shù)據(jù)回發(fā)到服務器時瀏覽器使用的編碼類型岂津。 下邊是說明: application/x-www-form-urlencoded: 窗體數(shù)據(jù)被編碼為名稱/值對虱黄。這是標準的編碼格式。 multipart/form-data: 窗體數(shù)據(jù)被編碼為一條消息吮成,頁上的每個控件對應消息中的一個部分橱乱。 text/plain: 窗體數(shù)據(jù)以純文本形式進行編碼,其中不含任何控件或格式字符粱甫。
application/x-www-form-urlencoded
這應該是最常見的 POST 提交數(shù)據(jù)的方式了泳叠。瀏覽器的原生
首先,Content-Type 被指定為 application/x-www-form-urlencoded茶宵;其次危纫,提交的數(shù)據(jù)按照 key1=val1&key2=val2 的方式進行編碼,key 和 val 都進行了 URL 轉(zhuǎn)碼乌庶。大部分服務端語言都對這種方式有很好的支持种蝶。例如 PHP 中,$_POST['title'] 可以獲取到 title 的值瞒大,$_POST['sub'] 可以得到 sub 數(shù)組螃征。
很多時候,我們用 Ajax 提交數(shù)據(jù)時透敌,也是使用這種方式盯滚。例如 JQuery 和 QWrap 的 Ajax,Content-Type 默認值都是「application/x-www-form-urlencoded;charset=utf-8」酗电。
multipart/form-data
這又是一個常見的 POST 數(shù)據(jù)提交的方式淌山。我們使用表單上傳文件時,必須讓
POST?http://www.example.com?HTTP/1.1
Content-Type:multipart/form-data;?boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition:?form-data;?name="text"title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition:?form-data;?name="file";?filename="chrome.png"Content-Type:?image/png
PNG?...?content?of?chrome.png?...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
這個例子稍微復雜點顾瞻。首先生成了一個 boundary 用于分割不同的字段泼疑,為了避免與正文內(nèi)容重復,boundary 很長很復雜荷荤。然后 Content-Type 里指明了數(shù)據(jù)是以 multipart/form-data 來編碼退渗,本次請求的 boundary 是什么內(nèi)容。消息主體里按照字段個數(shù)又分為多個結(jié)構(gòu)類似的部分蕴纳,每部分都是以--boundary開始会油,緊接著是內(nèi)容描述信息,然后是回車古毛,最后是字段具體內(nèi)容(文本或二進制)翻翩。如果傳輸?shù)氖俏募夹恚€要包含文件名和文件類型信息。消息主體最后以--boundary--標示結(jié)束嫂冻。關于 multipart/form-data 的詳細定義胶征,請前往 rfc1867 查看。
這種方式一般用來上傳文件桨仿,各大服務端語言對它也有著良好的支持睛低。
上面提到的這兩種 POST 數(shù)據(jù)的方式,都是瀏覽器原生支持的服傍,而且現(xiàn)階段標準中原生
隨著越來越多的 Web 站點钱雷,尤其是 WebApp,全部使用 Ajax 進行數(shù)據(jù)交互之后吹零,我們完全可以定義新的數(shù)據(jù)提交方式罩抗,給開發(fā)帶來更多便利。
application/json
application/json 這個 Content-Type 作為響應頭大家肯定不陌生灿椅。實際上澄暮,現(xiàn)在越來越多的人把它作為請求頭,用來告訴服務端消息主體是序列化后的 JSON 字符串阱扬。由于 JSON 規(guī)范的流行泣懊,除了低版本 IE 之外的各大瀏覽器都原生支持 JSON.stringify,服務端語言也都有處理 JSON 的函數(shù)麻惶,使用 JSON 不會遇上什么麻煩馍刮。
JSON 格式支持比鍵值對復雜得多的結(jié)構(gòu)化數(shù)據(jù),這一點也很有用窃蹋。記得我?guī)啄昵白鲆粋€項目時卡啰,需要提交的數(shù)據(jù)層次非常深,我就是把數(shù)據(jù) JSON 序列化之后來提交的警没。不過當時我是把 JSON 字符串作為 val匈辱,仍然放在鍵值對里,以 x-www-form-urlencoded 方式提交杀迹。
Google 的 AngularJS 中的 Ajax 功能亡脸,默認就是提交 JSON 字符串。例如下面這段代碼:
var?data?=?{'title':'test',?'sub'?:?[1,2,3]};
$http.post(url,?data).success(function(result)?{
...
});
最終發(fā)送的請求是:
BASHPOST?http://www.example.com?HTTP/1.1
Content-Type:?application/json;charset=utf-8
{"title":"test","sub":[1,2,3]}
這種方案树酪,可以方便的提交復雜的結(jié)構(gòu)化數(shù)據(jù)浅碾,特別適合 RESTful 的接口。各大抓包工具如 Chrome 自帶的開發(fā)者工具续语、Firebug垂谢、Fiddler,都會以樹形結(jié)構(gòu)展示 JSON 數(shù)據(jù)疮茄,非常友好滥朱。但也有些服務端語言還沒有支持這種方式根暑,例如 php 就無法通過 $_POST 對象從上面的請求中獲得內(nèi)容。這時候徙邻,需要自己動手處理下:在請求頭中 Content-Type 為 application/json 時排嫌,從php://input里獲得原始輸入流,再json_decode成對象鹃栽。一些 php 框架已經(jīng)開始這么做了躏率。
angularjs默認就是采用這種模式躯畴,如果需要民鼓,更改angular請求模式,一般請求:
$http({
method:?'POST',
cache:?false,
data:?data,
headers:?{?'Content-Type':?'application/x-www-form-urlencoded;?charset=UTF-8'},
transformRequest:?function(obj)?{
console.log('?$httpProvider.defaults.transformRequest?=?function(obj)?{');
console.log(obj);
var?str?=?[];
for?(var?p?in?obj)
str.push(encodeURIComponent(p)?+?"="?+?encodeURIComponent(obj[p]));
return?str.join("&");
},
url:?"syf-merchant/uploadMerchantRegPic"
}).success(function?(response)?{
}).error(function?()?{
CommonService.showMessage('上傳失敗蓬抄,請稍后再試')
})
};
當然丰嘉,也可以,直接攔截所有請求嚷缭,轉(zhuǎn)換:
/*?我的攔截器?*/
$httpProvider.defaults.headers.post['Content-Type']?=?'application/x-www-form-urlencoded;charset=UTF-8';
$httpProvider.defaults.transformRequest?=?function(obj)?{
console.log('?$httpProvider.defaults.transformRequest?=?function(obj)?{');
console.log(obj);
var?str?=?[];
for?(var?p?in?obj)
str.push(encodeURIComponent(p)?+?"="?+?encodeURIComponent(obj[p]));
return?str.join("&");
};
參考文章:
https://imququ.com/post/four-ways-to-post-data-in-http.html
http://www.cnblogs.com/sunxucool/archive/2012/12/11/2813113.html
轉(zhuǎn)載請注明出處:http://www.zhoulujun.cn/zhoulujun/html/webfront/SGML/web/2017_0719_8034.html