以前一篇文章(表單提交時編碼類型enctype詳解)介紹了表單屬性enctype
的編碼類型,今天來說一講Ajax方式提交表單時經常使用的編碼類型。前端
用Ajax方式提交表單,決定編碼類型的是請求頭中Content-Type
,不一樣的值對應不一樣的提交和回調處理方式。並且,在項目中咱們會用到前端的庫或者框架,他們對於不一樣的Content-Type
也有不一樣的參數寫法,本文將以jQuery和AngularJS,加上XMLHttpRequest共三種方式爲例,詳細介紹不一樣Content-Type
的發送請求的方式。
本文考慮的Content-Type
類型,共有以下幾種:jquery
application/x-www-form-urlencodedajax
multipart/form-datajson
text/plainsegmentfault
application/json後端
text/xml瀏覽器
下面將介紹XMLHttpRequest、jQuery和AngularJS三種異步提交方式,及對應的每一種Conten-Type類型。app
XMLHttpRequest對象用於向後端收發數據請求,現代瀏覽器都支持(IE要用ActiveXObject實現相同功能,本文就不討論了)。框架
後續代碼將假設已經得到了XMLHttpRequest對象,其名爲req
。下面將介紹XMLHttpRequest對象用常見的五種Content-Type
發送數據的方式。異步
這種Content-Type
要求數據按照key1=value1&key2=value2
的格式發送給後端,且其中的特殊字符須要轉義成%HH
的形式。
首先,須要用encodeURIComponent()
函數編碼表單數據,代碼以下。
/* data參數爲表單數據組成的對象,dataToSend爲待發送給後端的數據 */ var tempArr = []; for (var key in data) { if (data.hasOwnProperty(key)) { tempArr.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key])); } } var dataToSend = tempArr.join('&');
接着,設置請求頭部的Content-Type
,發送數據,代碼以下。
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); req.send(dataTosend);
這種Content-Type
類型多用來提交文件,咱們採用HTML5的FormData對象來構建提交的數據。FormData對象的瀏覽器支持狀況見:FormData對象的瀏覽器支持狀況。
基本上現代瀏覽器都支持,IE11如下不支持,不支持的建議用ajaxForm之類的jquery的文件提交插件吧。
首先,用FormData對象構建欲提交的數據,代碼以下。
/* data參數爲表單數據組成的對象,dataToSend爲待發送給後端的數據 */ var dataToSend = new FormData(); // HTML5對象, IE11如下不支持 for (var key in data) { if (data.hasOwnProperty(key)) { dataToSend.append(key, data[key]); } } // dataToSend就是FormData對象,可直接傳給後端 dataToSend
接着,直接發送給後端,注意這種類型的發送方式,不能設置請求頭部的Content-Type
,應交給瀏覽器來處理(設定Boundary等工做)。
req.send(dataToSend);
若是請求頭部沒有設定Content-Type
,且數據既不是FormData
也不是XML Document
(將在xml小節中介紹),則Content-Type
默認爲text/plain
。
這種方式的代碼很簡單,直接發送字符串便可,代碼以下。
req.send('...(此處是字符串格式的數據)');
JSON格式的數據,後端和各類移動端都很方便處理,用這種MIME類型時,須要將數據對象轉換成JSON串。
首先,轉換數據成JSON串;而後,設定請求頭部的Content-Type
,就能夠發數據了。代碼以下。
/* data參數爲表單數據組成的對象 */ req.send( JSON.stringify(data) );
目前沒有遇到過要用XML的狀況,大部分均可用JSON代替,爲了完整起見,我也順便總結一下。
首先,構建XML文檔對象,存入表單數據,代碼以下。
/* data參數爲表單數據組成的對象,dataToSend爲待發送給後端的數據 */ var dataToSend = document.implementation.createDocument("", "formdata", null); var tempData = dataToSend.documentElement; for (var key in data) { if (data.hasOwnProperty(key)) { var keyElement = doc.createElement(key); keyElement.appendChild(doc.createTextNode(data[key])); tempData.appendChild(keyElement); } } /* xml文檔格式示意: <formdata> <key1> value1 </key1> <key2> value2 </key2> </formdata> */
以後,與multipart/form-data
同樣,直接發送數據,不需設置Content-Type
。
req.send(dataToSend);
multipart/form-data
與text/xml
不須要設置請求頭的Content-Type
;
關於method
,以上都是POST
方式,如果GET
方式是沒有請求數據體的,數據直接加在URL後面;
text/xml:用responseXML
application/json:須要先JSON化,JSON.parse( responseText )
其餘:就直接用responseText
jQuery中默認的表單提交方式,與XMLHttpRequest不一樣的地方在於:數據的URL方式編碼,由jQuery來作,只須要在$.ajax({})
參數中設置processData = true
(這也是默認,可省略)。
代碼以下。
/* dataToSend爲Object類型的表單數據,不然jQuery會拋出異常 */ $.ajax({ method: 'POST', url: '...', data: dataToSend, contentType: 'application/x-www-form-urlencoded', // 可省略 processData: true, // 可省略 success: function() {...} });
注意:若採用GET
方式,則將method
改成GET便可,不須要在url後面加上數據。
這種MIME類型的提交方式,適合用於上傳文件。
首先,對錶單數據構建成FormData的HTML5對象,代碼以下。
/* dataToSend 是FormData對象,可直接做爲數據傳輸到後端 */ var dataToSend= new FormData(); // HTML5對象, IE11如下不支持 for (var key in data) { if (data.hasOwnProperty(key)) { dataToSend.append(key, data[key]); } }
以後,用$.ajax()
方法傳輸數據。
注意:processData
與contentType
必須設定爲false
,前者是由於避免FormData
對象被轉換成URL編碼,後者則是由於須要靠瀏覽器添加multipart/form-data
類型的boundary。
$.ajax({ method: 'POST', url: '...', data: dataToSend, // dataToSend 是FormData對象 contentType: false, // contentType 必須設置爲false processData: false, // processData 必須設置爲false success: function() { ... } });
用該類型提交,則直接傳輸字符串。
$.ajax({ method: 'POST', url: '...', data: dataToSend, contentType: 'text/plain', processData: false, // processData 設置爲false則不會轉換成URL編碼 success: function() { ... } });
用該類型提交,則傳輸JSON字符串,因此要用函數JSON.stringify()
處理表單數據。
/* data 爲表單Object類型的數據 */ dataToSend = JSON.stringify(data); $.ajax({ method: 'POST', url: '...', data: dataToSend, contentType: 'application/json', processData: false, // processData 設置爲false則不會轉換成URL編碼 success: function() { ... } });
注意:若後端也返回JSON字符串時,success
回調函數裏接受到的數據參數仍爲字符串,須要轉換成Object
類型。
(而Angular不須要)
$.ajax({ ... success: function(data) { var jsonData = JSON.parse(data); ... } });
首先,構建XML文檔對象,存入表單數據,代碼以下。
/* data參數爲表單數據組成的對象,dataToSend爲待發送給後端的數據 */ var dataToSend = document.implementation.createDocument("", "formdata", null); var tempData = dataToSend.documentElement; for (var key in data) { if (data.hasOwnProperty(key)) { var keyElement = doc.createElement(key); keyElement.appendChild(doc.createTextNode(data[key])); tempData.appendChild(keyElement); } } /* xml文檔格式示意: <formdata> <key1> value1 </key1> <key2> value2 </key2> </formdata> */
以後,發送數據dataToSend
,代碼以下。
$.ajax({ method: 'POST', url: '...', data: dataToSend, contentType: false, // contentType 可設爲false也可寫成具體的'text/xml'等 processData: false, // processData 必須設爲false success: function() { ... } });
用這種MIME類型提交表單數據,則須要對錶單數據進行URL編碼,用$.param(data)
函數,代碼以下。
$http({ method: 'POST', url: '...', data: $.param(dataToSend), headers: { 'Content-Type': 'application/x-www-form-urlencoded'} ).success(...);
首先,該類型若是要上傳文件,那麼Angular爲了獲取文件,推薦寫成指令。代碼以下。
.directive("fileReader", [function () { return { restrict: 'AE', scope: { fileReader: "=" // HTML中的file-reader做爲存放文件對象的變量 }, link: function (scope, element) { element.bind("change", function (changeEvent) { scope.$apply(function () { scope.fileReader = changeEvent.target.files[0]; }); }); } } }]) /* HTML結構以下 */ <input type="file" name="key1" file-reader="formData.file[1]">
而後,須要用FormData
對象來包裝表單數據並傳輸,建議寫在$http
服務的transformRequest
選項中;
另外,與jQuery相似其中的請求頭Content-Type
要設置爲undefined
。代碼以下。
$http({ method: 'POST', url: '...', data: dataToSend, headers: { 'Content-Type': undefined // 必須設置爲undefined }, transformRequest: function(data) { var tempFormData = new FormData(); // HTML5對象, IE11如下不支持 for (var key in data) { if (data.hasOwnProperty(key)) { tempFormData.append(key, data[key]); } } return tempFormData; } }).success(...)
以字符串的方式提交表單數據,代碼以下。
$http({ method: 'POST', url: '...', data: dataToSend, headers: { 'Content-Type': 'text/plain' }).success(...)
以JSON字符串的方式提交表單數據,用JSON.stringify()
函數轉換,代碼以下。
$http({ method: 'POST', url: '...', data: JSON.stringify(dataToSend), headers: { 'Content-Type': 'application/json' }).success(...)
注意:可是在success
函數裏接受到的參數,就是Object
對象,不須要和jQuery同樣用JSON.parse()
轉換。
與multipart/form-data
相似,在transformRequest
中構建XML Document
,請求頭中的Content-Type
設置爲undefined
或text/xml
等,代碼以下。
$http({ method: 'POST', url: '...', data: dataToSend, headers: { 'Content-Type': undefined // 設置爲undefined或'text/xml'等 }, transformRequest: function(data) { var doc = document.implementation.createDocument("", "formdata", null); var tempData = doc.documentElement; for (var key in data) { if (data.hasOwnProperty(key)) { var keyElement = doc.createElement(key); keyElement.appendChild(doc.createTextNode(data[key])); tempData.appendChild(keyElement); } } return doc; } }).success(...)
Angular用GET方式提交表單數據,應該用$http
服務的params
而不是data
來傳數據,params
能夠直接傳入Object
類型數據,代碼以下。
$http({ method: 'GET', url: '...', params: dataToSend }).success(...)