原理說明
Ajax的原理簡單來說通過XmlHttpRequest對象來向服務(wù)器發(fā)異步請求,從服務(wù)器獲得數(shù)據(jù),然后用javascript來操作DOM而更新頁面。XMLHttpRequest是ajax的核心機(jī)制,其原理此文不做闡述。通過對XMLHttpRequest對象的屬性和方法的設(shè)置,與服務(wù)端之間進(jìn)行基于http請求的消息傳送。例如,XMLHttpRequest對象的setRequestHeader()方法是用來設(shè)置請求頭的。這些過程都被封裝在ajax中。在jquery ajax里,發(fā)送信息至服務(wù)器時內(nèi)容編碼類型的設(shè)置是通過contentType字段表示的。dataType表示預(yù)期服務(wù)器返回的數(shù)據(jù)類型。請求成功后的回調(diào)函數(shù)success中將返回根據(jù) dataType 參數(shù)進(jìn)行處理后的數(shù)據(jù)。
這里之所以提到contentType這個字段,是因為它表示數(shù)據(jù)實體的類型,前后端要約定一致,通常前端應(yīng)根據(jù)后端的要求傳送對應(yīng)的contentType類型。類似于ajax的框架很多,它們都是基于XmlhttpRequest這個對象的,只是數(shù)據(jù)封裝的形式略有不同。所以對此文content-type數(shù)據(jù)類型的理解,也有助于其他框架的數(shù)據(jù)類型傳遞時遇到的問題解決。
常見解決方式
遇到數(shù)據(jù)傳遞http請求的狀態(tài)碼為400時,通常會對content-type類型進(jìn)行修改.
項目中常見的content-type有三種
?application/x-www-form-urlencoded
application/x-www-form-urlencoded是常用的POST 提交數(shù)據(jù)的方式,普通的表單提交,或者js發(fā)包,如果不設(shè)置 content-type 屬性,默認(rèn)都是通過這種方式
?application/json
現(xiàn)在越來越多的人把它作為請求頭,用來告訴服務(wù)端消息主體是序列化后的 JSON 字符串。application/json用來告訴服務(wù)端消息主體是序列化后的 JSON 字符串,JSON 格式支持比鍵值對復(fù)雜得多的結(jié)構(gòu)化數(shù)據(jù)。
?multipart/form-data
使用表單上傳文件時,必須讓 form 的 enctyped 等于’multipart/form-data’。
如下是從基于JQuery文件上傳插件ajaxfileupload.js中拷出來的一段代碼,能幫助理解。
if (form.encoding) {
jQuery(form).attr('encoding', 'multipart/form-data');
}
else {
jQuery(form).attr('enctype', 'multipart/form-data');
}
數(shù)據(jù)發(fā)送時需要與后端之間協(xié)商好傳送的數(shù)據(jù)類型,那么接收時也是同理的,接收時,ajax用到的字段是data-type。
特別說明,有時候content-type是后臺要求的application/json,但是仍然報http碼為400的錯誤,這是因為ajax內(nèi)部會對data數(shù)據(jù)進(jìn)行序列化轉(zhuǎn)為字符串,而’自動’轉(zhuǎn)為的字符串并非后臺需要的字符串,需要在被自動轉(zhuǎn)為字符串前先手動轉(zhuǎn)為字符串(即JSON.stringify(data)),已經(jīng)是字符串了就不會被自動轉(zhuǎn)為字符串,詳見案例分析。
關(guān)于data-type簡單說明一下:"json"表示返回 JSON 數(shù)據(jù);"text"表示返回純文本字符串;"jsonp"表示JSONP 格式;"script"表示返回純文本 JavaScript 代碼。
案例解析
在后端已確定采用json形式傳遞的前提下,當(dāng)前端向后端傳送如下圖一所示包含對象數(shù)組的數(shù)據(jù)對象時,采用如下代碼一中的代碼進(jìn)行請求,該請求并沒有成功。其中代碼一中將contentType設(shè)為 "application/json; charset=utf-8"。
圖一
代碼一:
$.ajax({
url: basePath + "/visitor/addVisitor",
data: resultObj,
plugin: false,
contentType: "application/json; charset=utf-8",
success: function (data) {
$.toast({
message: "添加成功",
state: true
});
}
});
此時,查看瀏覽器中network,如下圖二所示:
圖二
顯然請求沒有成功,報了400的錯誤。
原因如下:
通過查看jquery源碼,我們發(fā)現(xiàn),ajax接收的數(shù)據(jù)最終都將轉(zhuǎn)為字符串形式,如下是從jquery源碼中截取的一段代碼:
// Convert data if not already a string
if ( s.data && s.processData && typeof s.data !== "string" ) {
s.data = jQuery.param( s.data, s.traditional );
}
綜上,解決執(zhí)行代碼一時出現(xiàn)的http請求為400的情況,需將data自己手動轉(zhuǎn)為JSON字符串(JSON.stringify(data)),這樣就無需走JQuery里面的param函數(shù)進(jìn)行序列化轉(zhuǎn)換了。也就是說避免出現(xiàn)圖二箭頭所示的錯誤情況,圖二所示的情況是將接收的對象默認(rèn)序列化為鍵值對的形式。
如下附上正確的代碼:
$.ajax({
url: basePath + "/visitor/addVisitor",
data: JSON.stringify(resultObj),
plugin: false,
contentType: "application/json; charset=utf-8",
success: function (data) {
$.toast({
message: "添加成功",
state: true
});
}
});
總結(jié)
案例中,content-type是對的,是前后臺協(xié)商一致的application/json,但是傳輸?shù)臄?shù)據(jù)data必須先進(jìn)行JSON.stringify(data),原因是前后端傳送的必須是字符串,可以通過查看JQuery源碼得知,如果data不是字符串,JQuery內(nèi)部會將其進(jìn)行序列化轉(zhuǎn)為字符串,而序列化后的數(shù)據(jù)并非后端需要的,導(dǎo)致http狀態(tài)碼為400的錯誤。
Ajax的屬性配置均是基于對XmlhttpRequest對象的方法調(diào)用的封裝。對其深入理解,一方面需要理解http協(xié)議的原理,另一方面需要參照xmlhttpRequest對象原理讀懂jquery ajax源碼。對ajax理解也有助于理解其他基于xmlhttpRequest對象封裝的框架。