DreamPig 2019-06-27
说起ajax,大家都不陌生。但是由于目前很多框架或者库等都对网络请求做了封装,导致了很多初学者只知其然而不知其所以然。所以今天我们就详细了解一下ajax的实现原理和封装ajax的关键步骤。
ajax的核心是XMLHttpRequest对象。首先我们先创建一个XMLHTTPRequest对象 var xhr = new XMLHttpRequest();。
注意:本文所提及的内容不兼容古老的IE,有想了解的同学自行查阅ActiveXObject相关内容。
在使用XMLHttpRequest对象的第一步,我们首先要调用open方法来初始化请求参数,xhr.open('get','/test',true),虽然名字叫open,但是此时请求还并没有发送。
open(method, url[, async, username, password])
如果调用了open方法后再次对它进行调用,则相当于调用了abort方法,abort方法我们在后面介绍。
如果我们想为为请求绑定一些操作,这个时候就可以开始啦。常用的操作有如下几个:
setRequestHeader(key, value)
顾名思义,这个方法用于设置请求头内容。
overrideMimeType(type)
重写服务器返回的MIME类型。通过这个方法可以告诉服务器你想要的数据类型。
注意:以上这些操作必须定义在send方法之前。否则,就拿setRequestHeader来说,你都把请求发出去了再设置还有什么用?
这个时候,我们就可以通过调用send 方法来发送请求了,xhr.send(null)。
send(data)
发送请求,如果是同步请求的话,会阻塞代码的执行,直至收到服务器响应才会继续。
readyStateChanhe()
每次readyState的值改变的时候都会触发这个函数。
getResponseHeader(name)
获取指定响应头部的值,参数是响应头部的名称,并且不区分大小写。
getAllResponseHeaders()
获取服务器发送的所有HTTP响应的头部。
在这里我们穿插几个概念,readyState,这个属性表明了请求的状态,伴随HTTP请求的整个生命周期,它的值表明此时请求所处的阶段,具体如下:
readyState
| 数值 | 描述 |
|---|---|
| 0 | 初始化,open()尚未调用 |
| 1 | open()已经调用,但是send未调用 |
| 2 | 已获取到返回头信息 |
| 3 | 正在下载返回体信息 |
| 4 | 请求完成 |
还有几个较为常用的属性
| 名称 | 含义 |
|---|---|
| responseText | 响应的文本 |
| status | 响应的状态码 |
| statusText | 响应的状态信息 |
| responseXML | 响应内容是“text/xml”或者是“application/xml”格式的时候,这个属性的值就是响应数据的XMLDOM文档。 |
我们用下面这段代码做个测试
var xhr = new XMLHttpRequest();
console.log(xhr.readyState)
xhr.onreadystatechange = function(){
console.log('------')
console.log('readyState:' + xhr.readyState)
console.log('ResponseHeaders:' + xhr.getAllResponseHeaders())
console.log('ResponseText:' + xhr.responseText.length)
console.log('------')
}
xhr.open('get','/')
xhr.send(null)下图我们可以直观的看到在创建了XMLHttpRequest对象的时候,readyState的值为0。

然后我们定义了onreadystatechange函数,让其打印一些属性,并调用open方法,此时readyState变为1。

最后我们调用send方法,可以看到经历了如下过程:

abort()
取消响应,调用这个方法会终止已发送的请求。我们尝试在之前的代码最后加一句。
xhr.abort(); console.log(xhr.readyState);


也就是说,send执行以后,并没有去尝试请求数据,而是直接取消掉了,并且我们发现abort会将readyState的值置为0。
除此之外,XMLHttpRequest还有一个很重要的属性withCredentials,cookie在同域请求的时候,会被自动携带在请求头中,但是跨域请求则不会,除非把withCredentials的值设为true(默认为false)。同时需要在服务端的响应头部中设置Access-Control-Allow-Credentials:true。不仅如此Access-Control-Allow-Origin的值也必须为当前页面的域名。
到此为止,我们终于讲完了XMLHttpRequest的一些常用概念。接下来,我们尝试自己封装一个支持get和post的简易jax请求。
function ajax(url, option){
option = option || {};
var method = (option.method || 'GET').toUpperCase(),
async = option.async === undefined ? true : option.async,
params = handleParams(option.data);
var xhr = new XMLHttpRequest();
if(async){
xhr.onreadystatechange = function () {
if (xhr.readyState == 4){
callback(option,xhr);
}
};
}
if (method === 'GET'){
xhr.open("GET",url + '?' + params, async);
xhr.send(null)
}else if (method === 'POST'){
xhr.open('POST', url, async);
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send(params);
}
if(!async){
callback(option,xhr);
}
function callback(opt,obj){
var status = obj.status;
if (status >= 200 && status < 300 ){
opt.success && opt.success(obj.responseText,obj.responseXML);
}else{
opt.fail && opt.fail(status);
}
}
function handleParams(data) {
var arr = [];
for (var i in data) {
arr.push(encodeURIComponent(i) + '=' + encodeURIComponent(data[i]));
}
return arr.join('&');
}
}
// 测试调用
ajax('/xxx',{
method:'POST',
data:{
key: 'test'
},
success:function(){
console.log('success')
},
fail:function(){
console.log('fail')
}
});其实ajax实现原理并不复杂,复杂的是容错、兼容性等的处理,使用的时候尽量使用库或者框架提供的封装,避免不必要的漏洞。
感谢@虾哔哔的提问,这里做个简单的补充说明。
async是一个可选的布尔值参数,默认为true,意味着是否执行异步操作,如果值为false,则send()方法不会返回任何东西,直到接受到了服务器的返回数据。如果为值为true,一个对开发者透明的通知会发送到相关的事件监听者。这个值必须是true,如果multipart 属性是true,否则将会出现一个意外。
根据我的分析,当async为false的时候,readyState会在send方法之后直接由1变成4。也就是说异步模式,send方法会立刻返回。同步模式下,只有响应完全接受后,send才会返回。
另外,由于同步模式会阻塞,较新版本的Chrome在主线程上的同步请求已被弃用。
结束数据方法的参数,该如何定义?-- 集合为自定义实体类中的结合属性,有几个实体类,改变下标就行了。<input id="add" type="button" value="新增visitor&quo
本文实例讲述了php+ ajax 实现的写入数据库操作。分享给大家供大家参考,具体如下:。<input class="tel" type="text" placeholder="请输入您的手机号码&q