1. 背景介紹
AJAX即“Asynchronous JavaScript and XML”(異步的JavaScript與XML技術(shù)),指的是一套綜合了多項技術(shù)的瀏覽器端網(wǎng)頁開發(fā)技術(shù)。 Ajax的概念由杰西·詹姆士·賈瑞特所提出。
通過在后臺與服務器進行少量數(shù)據(jù)交換,Ajax可以使網(wǎng)頁實現(xiàn)異步更新。 這意味著可以在不重新加載整個網(wǎng)頁的情況下,對網(wǎng)頁的某部分進行更新。 傳統(tǒng)的網(wǎng)頁(不使用 Ajax)如果需要更新內(nèi)容,必須重載整個網(wǎng)頁頁面。
2. 知識剖析
a. 傳統(tǒng)的請求方式
傳統(tǒng)的web應用程序中,用戶向服務器發(fā)送一個請求,然后等待,服務器接受到用戶的請求然后響應。在這段時間內(nèi),用戶會只能等待數(shù)據(jù)傳輸完成,否則什么事情也不能做。這是因為以往的傳輸方式為同步處理方式。
b. Ajax的工作方式
和傳統(tǒng)的web應用不同,Ajax采取了異步交互避免了用戶請求-等待-應答交互方式的缺點。 Ajax在應用程序和服務器中引入了一個中間層---Ajax引擎,它是用Javascript編寫的,在一個隱藏的框架中運行。Ajax引擎負責呈現(xiàn)用戶界面, 以及代表用戶和服務器進行交互。Ajax引擎允許用戶和服務器進行異步的交互。這樣就可以實現(xiàn)一邊填寫表單一邊驗證的效果。
3. 常見問題
常見問題:
a. IE瀏覽器下面的緩存問題
b. 跨域問題
c. Ajax亂碼問題
d. 使用post時需要設置請求體的編碼格式
e. Ajax對象屬性的大小寫問題
4. 解決方案
a. 緩存問題:
在IE瀏覽器下面使用get請求時,如果第一次請求了數(shù)據(jù)之后IE會自動緩存數(shù)據(jù),如果下一次再發(fā)送同樣的 請求的時候瀏覽器會自動先去找緩存顯示出來,所以如果請求的數(shù)據(jù)有變化的時候,這里是看不到變化的。
解決辦法:
xhr.open("get","xxxx.aspx?_dc="+new Date().getTime(),true);
就是在請求的后面 加上_dc=。。。讓url變成唯一,或者是,改成post請求。
b. 跨域問題:
這是我們目前見到的最多的,也是最熟悉的一個問題。本地上面直接采用Nginx跨域?qū)崿F(xiàn)。注意 Nginx跨域可以同時配置多個接口的,就是多寫幾個location就好了,然后location后面帶的參數(shù)不一樣就可以了。
**c. Ajax亂碼問題 **
亂碼問題雖然我們目前遇到的不多,但是也屬于比較常見的一個問題了。出現(xiàn)的主要原因就是編碼不一致導致的。 如果出現(xiàn)亂碼問題了,首先檢查一下meta聲明的charset要和請求的頁面返回的charset一致。response.charset="gb2312 or utf-8"
d. 使用post提交的時候需要設置請求頭(編碼參數(shù))
XHR: content-Type: application/x-www-form-urlencoded
content-Type: multipart/form-data
jQuery: content-Type: application/x-www-form-urlencoded
$http: content-Type: application/json
http: content-Type: application/json
使用原生Ajax需要先設置請求參數(shù)(open):
xhr.open("post","xxxx.aspx",true);
xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");
e. Ajax對象屬性的大小寫問題:
if (xhr.readystate == 4) // IE ok / firefox error
if (xhr.readyState == 4)
同理還有屬性 responseText,responseXML。
習慣采用駝峰形式的寫法可以避免這個問題。
5. 編碼實戰(zhàn)
a. jQuery方法:
$.ajax({
url: "student-ajax/student", //端口
type: "POST", //方法
dataType: "json", //編碼格式
data: {
name: $("#names").val(),
qq: $("#QQs").val(),
},
success: function(data){
console.log(data);
if(data.code === 200){
alert($("#names").val() + "學員信息" +data.message);
}else{
alert(data.message);
}
},
error: function(data){
console.log(data);
alert("添加失敗");
}
});
b. AngularJS方法
$http({
method:'get', //同樣的參數(shù)
url:('/a/a/all/document?type=1&page='+$scope.page),
headers:{'Content-Type':'application/x-www-form-urlencoded'}
})
.success(function (response) { //處理方法
console.log(response.total);
console.log(response);
console.log(aaa);
// if (response.message === "查詢成功") {
$scope.userList = response.data;
$scope.userTotal = response.total;
$scope.page=response.page;
// console.log($scope.userList.total);
});
c. Angular 2 方法Obserable()
getLogMes(user: User): Observable<CurrentUser> {
const LOG_URL = 'xxx/xxx/xxx';
//json
// let body = JSON.stringify({'name': user.name, 'pwd': user.password});
// let headers = new Headers({'Content-Type': 'application/json'});
//string
let body = `name=${user.name}&pwd=${user.password}`;
let headers = new Headers({'Content-Type': 'application/x-www-form-urlencoded'});
let options = new RequestOptions({headers: headers});
return this.http.post(LOG_URL, body, options)
.map(this.extractData)
.catch(this.handleError);
}
該方法返回一個Obverable流,但是調(diào)用getLogMes()方法會并不會發(fā)送請求,還需要訂閱這個流才會發(fā)送請求。
d. Angular 2 方法Promise()
getLogMes(user: User): Promise<any> {
const LOG_URL = 'xxx/xxx/xxx';
//json
// let body = JSON.stringify({'name': user.name, 'pwd': user.password});
// let headers = new Headers({'Content-Type': 'application/json'});
//string
let body = `name=${user.name}&pwd=${user.password}`;
let headers = new Headers({'Content-Type': 'application/x-www-form-urlencoded'});
let options = new RequestOptions({headers: headers});
return this.http.post(LOG_URL, body, options)
.toPromise()
.map(this.extractData)
.catch(this.handleError);
}
返回一個Promise()對象,調(diào)用getLogMes()方法后會直接發(fā)送求。
e. 原生ajax
var request = new XMLHttpRequest(); // 新建XMLHttpRequest對象;
request.onreadystatechange = function () { // 狀態(tài)發(fā)生變化時,函數(shù)被回調(diào);
if (request.readyState === 4) { // 成功完成
// 判斷響應結(jié)果:
if (request.status === 200) {
// 成功,通過responseText拿到響應的文本:
} else {
// 失敗,根據(jù)響應碼判斷失敗原因:
}
} else {
// HTTP請求還在繼續(xù)...
}
}
// 發(fā)送請求:
request.open("POST","/skill-ajax/a/login",true);
request.setRequestHeader("Content-type","application/x-www-form-urlencoded");
request.send();
alert('請求已發(fā)送,請等待響應...');
// readyState值說明
// 0,初始化,XHR對象已經(jīng)創(chuàng)建,還未執(zhí)行open
// 1,載入,已經(jīng)調(diào)用open方法,但是還沒發(fā)送請求
// 2,載入完成,請求已經(jīng)發(fā)送完成
// 3,交互,可以接收到部分數(shù)據(jù)
// status值說明
// 200:成功
// 404:沒有發(fā)現(xiàn)文件、查詢或URl
// 500:服務器產(chǎn)生內(nèi)部錯誤
6. 擴展思考:常見的異步操作有哪些?
- 回調(diào)函數(shù):
funA(funB(...)); - Promise
(new Promise(functton (resolve, reject) {})) .then(funA) .then(funB) - Obervable
Rxjs的核心對象。
7. 參考文獻
a. 什么是跨域
b. AngularJS中then和success的區(qū)別
c. Ajax常見問題
d. JavaScript Promise迷你書