前言
最近一段时间一直很忙,直到年前才稍微闲暇下来,可能整理一下之前的一篇分享,也是对于ajax创建和使用的一种加深,你多久没有自己封装ajax了呢?
一、ajax的定义
Ajax是对Asynchronous JavaScript + XML的简写,技术的核心是XMLHttpRequest对象(简称 XHR)
1.XMLHttpRequest对象
IE5 是第一款引入 XHR 对象的浏览器。在 IE5 中,XHR 对象是通过 MSXML 库(有兴趣可以了解一下这个库,微软的)中的一个 ActiveX对象实现的。因此,在 IE 中可能会遇到三种不同版本的 XHR 对象,即
MSXML2.XMLHttp、
MSXML2.XMLHttp.3.0 、
MXSML2.XMLHttp.6.0。
使用MSXML 库中的 XHR 对象方式
//适用于 IE7 之前的版本
function createXHR(){
//activeXString是只createXHR对象自定义的属性 callee等同于new createXHR,函数本身
//activeXString 只能为两个属性,null或者是版本数组中的一个,也就是string
if (typeof arguments.callee.activeXString != "string"){
var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"],
i, len;
//从高版本创建,失败就跳过
for (i=0,len=versions.length; i < len; i++){
try {
new ActiveXObject(versions[i]);
//this.activeXString = 版本号,新增属性
arguments.callee.activeXString = versions[i];
break;
} catch (ex){
//跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}
这个函数会尽力根据 IE 中可用的 MSXML 库的情况创建最新版本的 XHR 对象。
IE7+、Firefox、Opera、Chrome 和 Safari 都支持原生的 XHR 对象,在这些浏览器中创建 XHR 对象 要像下面这样使用 XMLHttpRequest 构造函数。
var xhr = new XMLHttpRequest();
总的版本:
// 先检测原生 XHR 对象是否存在,如果存在则返回它的新实例
if (typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest();
// 如果原生对象不存在,则检测 ActiveX 对象
} else if (typeof ActiveXObject != "undefined"){
if (typeof arguments.callee.activeXString != "string"){
var versions = [ "MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
"MSXML2.XMLHttp"],
i, len;
for (i=0,len=versions.length; i < len; i++){
try {
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (ex){
//跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else {
throw new Error("No XHR object available.");
}
}
接下来就可以使用
var xhr = createXHR();
创建XHR对象啦。
二、XHR的用法
1. open()
xhr.open("get", "example.php", false);
要发送的请求的类型("get"、"post"等)、请求的 URL 和表示是否异步发送请求的布尔值用open()方法并不会真正发送请求,而只是启动一个请求以备发送。
2. send()
接收一个参数,即要作为请求主体发送的数据。 如果不需要通过请求主体发送数据,则必须传入 null,因为这个参数对有些浏览器来说是必需的。 在收到响应后,响应的数据会自动填充 XHR 对象的属性,相关的属性简介如下。
-
responseText:作为响应主体被返回的文本。
-
responseXML:如果响应的内容类型是"text/xml"或"application/xml",这个属性中将保 存包含着响应数据的 XML DOM 文档。
-
status:响应的 HTTP 状态。
-
statusText:HTTP 状态的说明。
同步请求
xhr.open("get", "example.txt", false);
xhr.send(null);
//状态代码为 304 表示请求的资源并没有被修改,可以直接使用浏览器中缓存的版本;当然,也意味着响应是有效的。
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
但多数情况下,我们还是要发送异步请求,才能让JavaScript 继续执行而不必等待响应。此时,可以检测 XHR 对象的 readyState 属性,该属性表示请求/响应过程的当前活动阶段。该属性可取:
-
0:未初始化。尚未调用 open()方法。
-
1:启动。已经调用 open()方法,但尚未调用 send()方法。
-
2:发送。已经调用 send()方法,但尚未接收到响应。
-
3:接收。已经接收到部分响应数据。
-
4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了。
只要 readyState 属性的值由一个值变成另一个值,都会触发一次readystatechange 事件。可以利用这个事件来检测每次状态变化后 readyState 的值。以上代码利用 DOM 0 级方法为 XHR 对象添加了事件处理程序,原因是并非所有浏览器都支持 DOM 2级方法(IE 9+才支持Dom2级方法)。
xhr.abort();
接收到响应之前还可以调用 abort()方法来取消异步请求
总体创建ajax:
//一、创建Ajax实例
let xhr = new XMLHttpRequest();//IE下为ActiveObject对象
//二、打开请求: 发送请求之前的一些配置项
//1.HTTP METHOD:GET/POST/PUT/DELETE/HEAD/OPTIONS/TRACE/CONNECT/
//2.url:接口地址
//3.async:设置Ajax的同步异步,默认是异步
//4.user-name/user-pass用户名和密码,一般不用
xhr.open(method, url, async, [user-name], [user-pass])
//三、事件监听:一般监听的都是readystatechange事件(Ajax状态改变事件),基于这个事件可以获取服务器返回的响应头响应主体
xhr.onreadystatechange = () => {
if(xhr.readyState === 4 && xhr.status === 200){
console.log(xhr.responseText);
}
};
//四、发送Ajax请求:从这步开始,当前Ajax任务开始,如果Ajax是同步的,后续代码不会执行,要等到Ajax状态成功后再执行
xhr.send([请求主体内容])
到这里从创建createXHR 到到xhr的发送到响应封装你学会了吗? 这可是一道经典面试手写代码题呢 ~ ?
三、XMLHttpRequest 2 级
XMLHttpRequest 1 级只是把已有的 XHR 对象的实现细节描述了出来。而 XMLHttpRequest 2 级则进一步发展了XHR。
1. FormData
现代 Web 应用中频繁使用的一项功能就是表单数据的序列化,XMLHttpRequest 2 级为此定义了
FormData 类型。
var data = new FormData();
data.append("name", "Nicholas");
append()方法接收两个参数:键和值,分别对应表单字段的名字和字段中包含的值。可以像 这样添加任意多个键值对儿。
// 也可以用表单元素的数据预先向其中填入键值对儿:
var data = new FormData(document.forms[0]);
实例:
var xhr = createXHR();
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("post","postexample.php", true);
// 添加FormData数据
var form = document.getElementById("user-info");
xhr.send(new FormData(form));
使用 FormData 的方便之处体现在不必明确地在 XHR 对象上设置请求头部。XHR 对象能够识别传入的数据类型是 FormData 的实例,并配置适当的头部信息。 支持 FormData 的浏览器有 Firefox 4+、Safari 5+、Chrome 和 Android 3+版 WebKit。
2. 超时设定
IE8 为 XHR 对象添加了一个 timeout 属性,表示请求在等待响应多少毫秒之后就终止。也是我们常使用的,就不多简介了
var xhr = createXHR();
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
try {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
} catch (ex){
//假设由 ontimeout 事件处理程序处理
}
}
};
xhr.open("get", "timeout.php", true);
xhr.timeout = 1000; //将超时设置为 1 秒钟(仅适用于 IE8+)
xhr.ontimeout = function(){
alert("Request did not return in a second.");
};
xhr.send(null);
3. overrideMimeType()
MDN
的定义:XMLHttpRequest 的 overrideMimeType 方法是指定一个MIME类型用于替代服务器指定的类型,被纳入XMLHttpRequest 2 级规范。使服务端响应信息中传输的数据按照该指定MIME类型处理。例如强制使流方式处理为"text/xml"类型处理时会被使用到,即使服务器在响应头中并没有这样指定。
var xhr = createXHR();
xhr.open("get", "text.php", true);
// 在send之前调用有效
xhr.overrideMimeType("text/xml");
xhr.send(null);
支持 overrideMimeType()方法的浏览器有 Firefox、Safari 4+、Opera 10.5 和 Chrome。
4.进度事件
Progress Events 规范是 W3C 的一个工作草案,定义了与客户端服务器通信有关的事件。这些事件最 早其实只针对 XHR 操作,但目前也被其他 API 借鉴。有以下 6 个进度事件。
- loadstart:在接收到响应数据的第一个字节时触发。
- progress:在接收响应期间持续不断地触发。
- error:在请求发生错误时触发。
- abort:在因为调用 abort()方法而终止连接时触发。
- load:在接收到完整的响应数据时触发。
- loadend:在通信完成或者触发 error、abort 或 load 事件后触发。
支持前 5 个事件的浏览器有 Firefox 3.5+、Safari 4+、Chrome、iOS 版 Safari 和 Android 版 WebKit。 Opera(从第 11 版开始)、IE 8+只支持 load 事件。目前还没有浏览器支持 loadend 事件。
这些事件大都很直观,但其中两个事件有一些细节需要注意。
5. load事件
Firefox 在实现 XHR 对象的某个版本时,曾致力于简化异步交互模型。最终,Firefox 实现中引入了
load 事件,用以替代readystatechange
事件。而 onload 事件处理程序会接收到一个 event 对象,其 target 属性就指向 XHR 对象实例,因而可以访问到 XHR 对象的所有方法和属性。。响应接收完毕后将触发 load 事件,因此也就没有必要去检查 readyState 属性了。
onload 事件处理程序会接收到一个event
对象,其target
属性就指 XHR
对象实例,因而可以访问到XHR
对象的所有方法和属性。然而,并非所有浏览器都为这个事件实现了适当的事件对象。结果,开发人员还是要像下面这样被迫使用 XHR 对象变量。
var xhr = createXHR();
xhr.onload = function(){
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
};
xhr.open("get", "altevents.php", true);
xhr.send(null);
只要浏览器接收到服务器的响应,不管其状态如何,都会触发 load 事件。而这意味着你必须要检 查 status 属性,才能确定数据是否真的已经可用了。Firefox、Opera、Chrome 和 Safari 都支持 load事件。
6. progress事件
对 XHR 的另一个革新是添加了progress事件,这个事件会在浏览器接收新数据期间周期性地触发。而onprogress事件处理程序会接收到一个event对象,其 target 属性是 XHR 对象,但包含着三个额外的属性:lengthComputable
、position
和 totalSize
。其中,
- lengthComputable是一个表示进度信息是否可用的布尔值,
- position 表示已经接收的字节数
- totalSize 表示根据
- Content-Length 响应头部确定的预期字节数。
有了这些信息,我们就可以为用户创建一个进度指示器了。下面展示了为用户创建进度指示器的一个示例。
var xhr = createXHR();
xhr.onload = function(event){
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
};
// open 之前调用,每次触发都会以新的状态信息更新 HTML 元素的内容
//如果响应头部中包含Content-Length 字段,那么也可以利用此信息来计算从响应中已经接收到的数据的百分比。
xhr.onprogress = function(event){
var divStatus = document.getElementById("status");
if (event.lengthComputable){
divStatus.innerHTML = "Received " + event.position + " of " +
event.totalSize +" bytes";
}
};
xhr.open("get", "altevents.php", true);
xhr.send(null);
四、跨资源共享
1.CORS
我们都知道ajax是同源策略,协议、域名、端口一致。
CORS(Cross-Origin Resource Sharing,跨源资源共享
是 W3C 的一个工作草案,定义了在必须访问跨源资源时,浏览器与服务器应该如何沟通。
CORS 背后的基本思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
var xhr = createXHR();
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("get", "http://www.somewhere-else.com/page/", true);
xhr.send(null);
Firefox 3.5+、Safari 4+、Chrome、iOS 版 Safari 和 Android 平台中的 WebKit 都通过 XMLHttpRequest
对象实现了对 CORS 的原生支持。 但跨域 XHR 对象也有一些限制,但为了安全这些限制是必需的。以下就是这些限制。
1.不能使用 setRequestHeader()设置自定义头部。
2.不能发送和接收 cookie。
3.调用 getAllResponseHeaders()方法总会返回空字符串。
Preflighted Reqeusts
CORS 通过一种叫做 Preflighted Requests 的透明服务器验证机制支持开发人员使用自定义的头部、GET 或 POST 之外的方法,以及不同类型的主体内容。在使用下列高级选项来发送请求时,就会向服务器发送一个 Preflight请求。这种请求使用OPTIONS方法,发送下列头部。
Origin:与简单的请求相同。
Access-Control-Request-Method:请求自身使用的方法。
Access-Control-Request-Headers:(可选)自定义的头部信息,多个头部以逗号分隔。
带凭据请求
默认情况下,跨源请求不提供凭据(cookie、HTTP 认证及客户端 SSL 证明 等 )。 通 过 将
withCredentials
属性设置为 true,可以指定某个请求应该发送凭据。如果服务器接受带凭据的请
求,会用下面的 HTTP 头部来响应。
Access-Control-Allow-Credentials: true
如果发送的是带凭据的请求,但服务器的响应中没有包含这个头部,那么浏览器就不会把响应交给 JavaScript(于是,responseText 中将是空字符串,status 的值为 0,而且会调用 onerror()事件处 理程序)。另外,服务器还可以在 Preflight 响应中发送这个 HTTP 头部,表示允许源发送带凭据的请求。
function createCORSRequest(method, url){
var xhr = new XMLHttpRequest();
//检测 XHR 是否支持 CORS 的最简单方式,就是检查是否存在 withCredentials 属性
if ("withCredentials" in xhr){
xhr.open(method, url, true);
//检测 XDomainRequest 对象是否存在 IE是XDomainRequest
} else if (typeof XDomainRequest != "undefined"){
vxhr = new XDomainRequest();
xhr.open(method, url);
} else {
xhr = null;
}
return xhr;
}
var request = createCORSRequest("get", "http://www.somewhere-else.com/page/");
if (request){
request.onload = function(){
//对 request.responseText 进行处理
};
request.send();
}
Firefox、Safari 和 Chrome 中的 XMLHttpRequest 对象与 IE 中的 XDomainRequest 对象类似,都
提供了够用的接口,因此以上模式还是相当有用的。这两个对象共同的属性/方法如下。
1.abort():用于停止正在进行的请求。
2.onerror:用于替代 onreadystatechange 检测错误。
3.onload:用于替代 onreadystatechange 检测成功。
4.responseText:用于取得响应内容。
5.send():用于发送请求。
以上成员都包含在 createCORSRequest()函数返回的对象中,在所有浏览器中都能正常使用。
四、其他跨域技术
1. 图像ping
原理:利用标签的src属性,图像 Ping 是与服务器进行简单、单向的跨域通信的一种方式。 请求的数据是通过查询字符串形式发送的,而响应可以是任意内容,但通常是像素图或 204 响应。
缺点:
1.只能发送 GET 请求
2.无法访问服务器的响应文本。
因此,图像 Ping 只能用于浏览器与服务器间的单向通信。
2. JSONP
JSONP是JSON withpadding(填充式 JSON 或参数式 JSON)的简写,是应用 JSON 的一种新方法,
JSONP 由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调 函数的名字一般是在请求中指定的。而数据就是传入回调函数中的JSON数据。
// 实例
http://freegeoip.net/json/?callback=handleResponse
原理:通过<script>
标签力不受限制地从其他域加载资源(不多说了!大家常用)
3. Comet
指的是一种更高级的 Ajax 技术,Ajax 是一种从页面向服务器请求数据的技术,而 Comet 则是一种服务器向页面推送数据的技术。Comet 能够让信息近乎实时地被推送到页面上,非常适合处理体育比赛的分数和股票报价
有两种实现 Comet 的方式:长轮询
和流
。长轮询是传统轮询(也称为短轮询)的一个翻版,即浏览器定时向服务器发送请求,看有没有更新的数据。
两者最大的区别:
【在于服务器如何发送数据】
-
短轮询是服务器立即发送响应,无论数据是否有效,
-
长轮询是等待发送响应。
轮询的优势是所有浏览器都支持,因为使用 XHR 对象和 setTimeout()就能实现。而你要做的就是决定什么时候发送请求。
第二种就是HTTP流</font>
:流不同于上述两种轮询,因为它在页面的整个生命周期内只使用一个 HTTP 连接。具体来说,就是浏览器向服务器发送一个请求,而服务器保持连接打开,然后周期性地向浏览器发送数据。
所有服务器端语言都支持打印到输出缓存然后刷新(将输出缓存中的内容一次性全部发送到客户端)的功能。而这正是实现 HTTP 流的关键所在。
// Firefox、Safari、Opera 和 Chrome 中,通过侦听 readystatechange 事件及检测 readyState的值是否为 3,就可以利用 XHR 对象实现 HTTP 流。
function createStreamingClient(url, progress, finished){
var xhr = new XMLHttpRequest(),
received = 0;
xhr.open("get", url, true);
xhr.onreadystatechange = function(){
var result;
//已经接收到响应数据
if (xhr.readyState == 3){
// readyState 值变为 3 时,responseText 属性中就会保存接收到的所有数据。此时,就需要比较此前接收到的 数据,决定从什么位置开始取得最新的数据
//只取得最新数据并调整计数器
result = xhr.responseText.substring(received);
received += result.length;
//调用 progress 回调函数
progress(result);
} else if (xhr.readyState == 4){
finished(xhr.responseText);
}
};
xhr.send(null);
return xhr;
}
// 创建一个流
var client = createStreamingClient("streaming.php", function(data){
alert("Received: " + data);
}, function(data){
alert("Done!");
});
所有浏览器都支持长轮询,而只有部分浏览器原生支持 HTTP 流。
现有API:
SSE(Server-Sent Events,服务器发送事件)是一种实现 Comet 交互的浏览器 API,既支持长轮询,也支持HTTP 流。SSE API用于创建到服务器的单向连接,服务器通过这个连接可以发送任意数量的数据。
Web Sockets 是一种与服务器进行全双工、双向通信的信道。与其他方案不同,Web Sockets 不使用 HTTP 协议,而使用一种自定义的协议。这种协议专门为快速传输小数据设计。虽然要求使用不同的 Web 服务器,但却具有速度上的优势
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!