本周,荷甲劲旅阿贾克斯在欧联杯四分之一决赛次回合中虽2-3落败,但凭借首回合两球优势,以总比分4-3将德甲强敌沙尔克04淘汰出局,拿到一个四强席位... ...
没错,作为一个球迷,最早听到阿贾克斯一词,还是因为这家荷兰足球甲级联赛俱乐部。但今天我们要研究的主角,是一种创建交互式网页应用的前端开发技术——AJAX(Asynchronous Javascript And XML)。
转自(做了少许改动):劳卜 2016年09月06日 https://segmentfault.com/a/11...
Ajax是目前很普遍的一门技术,也是很值得探讨和研究的一门技术。本文将针对Ajax的发展过程并结合其在不同库框架中的使用方式来和大家分享下Ajax的那些新老语法。——劳卜
Ajax简介
Ajax全称为“Asynchronous Javascript And XML”, 即“异步JavaScript和XML”的意思。通过Ajax我们可以向服务器发送请求,在不阻塞页面的情况下进行数据交互,也可以理解为异步数据传输。在Ajax的帮助下我们的网页只需局部刷新即可更新数据的显示,减少了不必要的数据量,大大提高了用户体验,缩短了用户等待的时间,使得web应用程序更小、更快,更友好。 当然以上都是司空见惯的内容了,作为一名合格的开发人员基本都再熟悉不过了,这里只为那些刚入门的新手做一个简单的介绍。更多的关于Ajax的简介请移步W3School进行了解:
http://www.w3school.com.cn/ph...
原生Ajax
基本上所有现代的浏览器都支持原生Ajax的功能,下面就来详细介绍下利用原生JS我们怎样来发起和处理Ajax请求。
1.获取XMLHttpRequest对象
var xhr = new XMLHttpRequest(); //获取浏览器内置的XMLHttpRequest对象
如果你的项目应用不考虑低版本IE,那么可以直接用上面的方法,所有现代浏览器 (Firefox、Chrome、Safari 以及 Opera) 都内建了 XMLHttpRequest 对象。如果需要兼容老版本IE(IE5、IE6),那么可以使用ActiveXObject对象:
var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
2.参数配置
有了XMLHttpRequest对象,我们还需要配置一些请求的参数信息来完成数据交互,利用open方法即可:
var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
if (xhr) {
xhr.open('GET', '/test/', true); //以GET请求的方式向'/test/'路径发送异步请求
}
open方法为我们创建了一个新的http请求,其中第一个参数为请求方式,一般为'GET'或'POST';第二个参数为请求url;第三个参数为是否异步,默认为true。
3.发送请求
配置完了基本参数信息,我们直接调用send方法发送请求,代码如下:
var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
if (xhr) {
xhr.open('GET', '/test/', true); //以GET请求的方式向'/test/'路径发送异步请求
xhr.send(); //调用send方法发送请求
}
这里需要注意的是如果使用GET方法传递参数,我们可以直接将参数放在url后面,比如'/test/?name=luozh&size=12';如果使用POST方法,那么我们的参数需要写在send方法里,如:
xhr.open('POST', '/test/', true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); //将请求头设置为表单方式提交
xhr.send('name=luozh&size=12');
最终会以Form Data的形式传递:
如果不设置请求头,原生Ajax会默认使用Content-Type是'text/plain;charset=UTF-8'的方式发送数据,如果按照上面的参数书写形式,我们最终传输的形式是这样的:
显然这并不是服务器期望的数据格式,我们可以这样写:
xhr.open('POST', '/test/', true);
xhr.send(JSON.stringify({name: 'luozh', size: 12}));
最终传输的格式如下:
这样我们可以直接传递JSON字符串给后台处理,当然后台也需要进行相应配置。
4.监测状态
发送完Ajax请求之后,我们需要针对服务器返回的状态进行监测并进行相应的处理,这里我们需要使用onreadystatechange事件,代码如下:
var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
if (xhr) {
xhr.open('GET', '/test/', true); //以GET请求的方式向'/test/'路径发送异步请求
xhr.send(); //调用send方法发送请求
xhr.onreadystatechange = function () { //利用onreadystatechange监测状态
if (xhr.readyState === 4) { //readyState为4表示请求响应完成
if (xhr.status === 200) { //status为200表示请求成功
console.log('执行成功');
} else {
console.log('执行出错');
}
}
}
}
上面我们利用onreadystatechange监测状态,并在内部利用readyState获取当前的状态。readyState一共有5个阶段,当其为4时表示响应内容解析完成,可以在客户端调用了。当readyState为4时,我们又通过status来获取状态码,状态码为200时执行成功代码,否则执行出错代码。
当然,我们可以用onload来代替onreadystatechange等于4的情况,因为onload只在状态为4的时候才被调用,代码如下:
xhr.onload = function () { //调用onload
if (xhr.status === 200) { //status为200表示请求成功
console.log('执行成功');
} else {
console.log('执行出错');
}
}
然而,需要注意的是,IE对onload这个属性的支持并不友好。除了onload还有:
onloadstart
onprogress
onabort
ontimeout
onerror
onloadend
等事件,有兴趣的同学可以亲自去实践它们的用处。
以上便是原生Ajax请求数据的常见代码。
其他库框架中的Ajax
1.jQuery中的Ajax
jQuery作为一个使用人数最多的库,其Ajax很好的封装了原生Ajax的代码,在兼容性和易用性方面都做了很大的提高,让Ajax的调用变得非常简单。下面便是一段简单的jQuery的Ajax代码:
$.ajax({
method: 'GET', //1.9.0版本之前用'type'
url: '/test/',
dataType: 'json'
}).done(function() {
console.log('执行成功');
}).fail(function() {
console.log('执行出错');
});
与原生Ajax不同的是,jQuery中默认的Content-type是'application/x-www-form-urlencoded; charset=UTF-8', 想了解更多的jQuery Ajax的信息可以移步官方文档:http://api.jquery.com/jquery....
2.Vue.js中的Ajax
Vue.js作为目前热门的前端框架,其本身并不包含Ajax功能,而是通过插件的形式额外在项目中引用,其官方推荐的Ajax插件为vue-resource,下面便是vue-resource的请求代码:
Vue.http.get('/test/').then((response) => {
console.log('执行成功');
}, (response) => {
console.log('执行出错');
});
vue-resource支持Promise API,同时支持目前的Firefox, Chrome, Safari, Opera 和 IE9+浏览器,在浏览器兼容性上不兼容IE8,毕竟Vue本身也不兼容IE8。想了解更多的vue-resource的信息可以移步github文档:https://github.com/pagekit/vu...
3.Angular.js中的Ajax
这里Angular.js中的Ajax主要指Angular的1.×版本,因为Angular2目前还不建议在生产环境中使用。
var myApp = angular.module('myApp', []);
var myCtrl = myApp.controller('myCtrl', ['$scope','$http',function($scope, $http){
$http({
method: 'GET',
url: '/test/',
headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
}).success(function (data) {
console.log('执行成功');
}).error(function () {
console.log('执行出错');
});
}]);
在Angular中,我们需要在控制器上注册一个$http的事件,然后才能在内部执行Ajax。Angular的Ajax默认的Content-type是'application/json;charset=UTF-8',所以如果想用表单的方式提交还需设置下headers属性。想了解更多的Angular Ajax的信息可以移步官方文档:https://docs.angularjs.org/ap...可能需要翻墙)
4.React中的Ajax
在React中我比较推荐使用fetch来请求数据,当然fetch不仅适用于React,在任何一种框架如上面的Vue、Angular中都可以使用,因为fetch已经被目前主流浏览器所支持,至于其主要功能和用法,我在下面会做下讲解。
Fetch API
Fetch API 是基于 Promise 设计,由于Promise的浏览器兼容性问题及Fetch API本身的兼容问题,一些浏览器暂时不支持Fetch API,浏览器兼容图如下:
当然我们可以通过使用一些插件来解决兼容性问题,比如:fetch-polyfill、es6-promise、fetch-ie8等。
使用Fetch我们可以非常便捷的编写Ajax请求,我们用原生的XMLHttpRequst对象和Fetch来比较一下:
XMLHttpRequst API
// XMLHttpRequst API
var xhr = new XMLHttpRequest();
xhr.open('GET', '/test/', true);
xhr.onload = function() {
console.log('执行成功');
};
xhr.onerror = function() {
console.log('执行出错');
};
xhr.send();
Fetch API
fetch('/test/').then(function(response) {
return response.json();
}).then(function(data) {
console.log('执行成功');
}).catch(function(e) {
console.log('执行出错');
});
可以看出使用Fetch后我们的代码更加简洁和语义化,链式调用的方式也使其更加流畅和清晰。随着浏览器内核的不断完善,今后的XMLHttpRequest会逐渐被Fetch替代。关于Fetch的详细介绍可以移步:传统 Ajax 已死,Fetch 永生
跨域Ajax
介绍了各种各样的Ajax API,我们不能避免的一个重要问题就是跨域,这里重点讲解下Ajax跨域的处理方式。
处理Ajax跨域问题主要有以下4种方式:
利用iframe
利用JSONP
利用代理
利用HTML5提供的XMLHttpRequest Level2
第1和第2种方式大家应该都非常熟悉,都属于前端的活,这里就不做介绍了,这里主要介绍第3和第4种方式。
利用代理的方式可以这样理解: 通过在同域名下的web服务器端创建一个代理: 北京服务器(域名:www.beijing.com)
上海服务器(域名:www.shanghai.com)
比如在北京的web服务器的后台(www.beijing.com/proxy-shanghaiservice.php)来调用上海服务器(www.shanghai.com/services.php)的服务,然后再把访问结果返回给前端,这样前端调用北京同域名的服务就和调用上海的服务效果相同了。
利用XMLHttpRequest Level2的方式需要后台将请求头进行相应配置:
// php语法
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET,POST');
以上的号可以替换成允许访问的域名,表示所有域名都可以访问。
由此可见,第3和第4种方式主要是后台的活,前端只需调用就可以。
总结
无论Ajax的语法多么多变,无论库和框架如何封装Ajax,其只是一种实现异步数据交互的工具,我们只需理解原生JS中Ajax的实现原理,了解XMLHttpRequest及promise的概念和流程,便可以轻松的在数据异步交互的时代游刃有余。
补充:
readyState的5个阶段(状态)
我觉得比较理想的解释方法应该以“状态:任务(目标)+过程+表现(或特征)”表达 模式来对这几个状态进行定义比较准确,而且让人容易理解。现试总结如下:
状态 | 任务(目标) + 过程 + 表现(或特征) |
---|---|
0 未初始化 | 此阶段确认XMLHttpRequest对象是否创建,并为调用open()方法进行初始化作好准备。值为0表示对象已经存在,否则浏览器会报错--对象不存在。但此时open()和send()方法还未调用 |
1 载入 | 此阶段对XMLHttpRequest对象进行初始化,即调用open()方法,根据参数(method,url,true)完成对象参数的设置。并调用send()方法开始向服务端发送请求。值为1表示正在向服务端发送请求。 |
2 载入完成 | 此阶段接收服务器端的响应数据。但获得的还只是服务端响应的原始数据,并不能直接在客户端使用。值为2表示已经接收完全部响应数据。并为下一阶段对数据解析做好准备。 |
3 交互 | 此阶段解析接收到的服务器端响应数据。即根据服务器端响应头部返回的MIME类型把数据转换成能通过responseBody、responseText或responseXML属性存取的格式,为在客户端调用作好准备。状态3表示正在解析数据。 |
4 完成 | 此阶段确认全部数据都已经解析为客户端可用的格式,解析已经完成。值为4表示数据解析完毕,可以通过XMLHttpRequest对象的相应属性取得数据。 |
可概括为,整个XMLHttpRequest对象的生命周期应该包含如下阶段:创建-初始化请求-发送请求-接收数据-解析数据-完成
在具体应用中,明确了readyState的五个状态(XMLHttpRequest对象的生命周期各个阶段)的含义,就可以消除对Ajax核心的 神秘感(语焉不详的背后要么是故弄玄虚,制造神秘感;要么就是“以其昏昏,使人昭昭”),迅速把握其实质,对减少学习中的挫折感和增强自信心都极其有益。
常用状态码
状态码的职责是当客户端向服务器端发送请求时,描述返回的请求结果。借助状态码,用户可以知道服务器端是正常处理了请求,还是出现了错误。
状态码由3位数字和原因短语组成,数字中第一位指定相应类别,后两位无分类,有以下5中响应类别。
状态码 | 类别 | 原因短语 |
---|---|---|
1XX | Informational(信息性状态码) | 接受的请求正在处理 |
2XX | Success(成功状态码) | 请求正常处理完毕 |
3XX | Redirection(重定向状态码) | 需要进行附加操作以完成请求 |
4XX | Client Error(客户端错误状态码) | 服务器无法处理请求 |
5XX | Server Error(服务器错误状态码) | 服务器处理请求出错 |
记录在RFC2616与WebDAV中的各种HTTP状态码加起来有60多种,但我们常用的就14种,想要了解更多,请移步:常用HTTP状态码。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。