刨根问底ajax原理与封装-阿里云开发者社区

开发者社区> 行者武松> 正文

刨根问底ajax原理与封装

简介:
+关注继续查看

说起ajax,大家都不陌生。但是由于目前很多框架或者库等都对网络请求做了封装,导致了很多初学者只知其然而不知其所以然。所以今天我们就详细了解一下ajax的实现原理和封装ajax的关键步骤。

ajax的核心是XMLHttpRequest对象。首先我们先创建一个XMLHTTPRequest对象var xhr = new XMLHttpRequest();

注意:本文所提及的内容不兼容古老的IE,有想了解的同学自行查阅ActiveXObject相关内容。


XMLHttpRequest

在使用XMLHttpRequest对象的第一步,我们首先要调用open方法来初始化请求参数,xhr.open('get','/test',true),虽然名字叫open,但是此时请求还并没有发送。

open(method, url[, async, username, password])

  • method:请求类型,例如GET,POST等
  • url:请求地址(这里有同源限制,就是我们经常会看到的跨域问题啦)
  • async:是否发送异步请求。可选参数,默认为true。
  • username&password:可选参数,授权验证使用的,但是我们一般不这么用,使用后请求变成这个样子了,http(s)://username:password@url。

如果调用了open方法后再次对它进行调用,则相当于调用了abort方法,abort方法我们在后面介绍。

如果我们想为为请求绑定一些操作,这个时候就可以开始啦。常用的操作有如下几个:

setRequestHeader(key, value)

顾名思义,这个方法用于设置请求头内容。

  • key:要设置的请求头名称
  • value:对应请求头的值

overrideMimeType(type)

重写服务器返回的MIME类型。通过这个方法可以告诉服务器你想要的数据类型。

注意:以上这些操作必须定义在send方法之前。否则,就拿setRequestHeader来说,你都把请求发出去了再设置还有什么用?

这个时候,我们就可以通过调用send 方法来发送请求了,xhr.send(null)

send(data)

发送请求,如果是同步请求的话,会阻塞代码的执行,直至收到服务器响应才会继续。

  • data:发送给服务器的数据。为了兼容不同的浏览器,即使是不需要传数据,也需要传入参数null。

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。

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

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

  1. send方法调用之后,readyState变为2,此时responseHeader已经获取到了,responseText为空;
  2. 响应数据开始下载,readyState变为3
  3. 响应数据下载结束,readyState变为4.我们可以发现此时responseText的长度比之前长。image

abort()

取消响应,调用这个方法会终止已发送的请求。我们尝试在之前的代码最后加一句。

xhr.abort();
console.log(xhr.readyState);
复制代码

imageimage

也就是说,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实现原理并不复杂,复杂的是容错、兼容性等的处理,使用的时候尽量使用库或者框架提供的封装,避免不必要的漏洞。




原文发布时间:2018年07月02日
原文作者:志如
本文来源掘金,如需转载请紧急联系作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,大概有三种登录方式:
2514 0
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
9560 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
8990 0
使用SSH远程登录阿里云ECS服务器
远程连接服务器以及配置环境
2122 0
使用OpenApi弹性释放和设置云服务器ECS释放
云服务器ECS的一个重要特性就是按需创建资源。您可以在业务高峰期按需弹性的自定义规则进行资源创建,在完成业务计算的时候释放资源。本篇将提供几个Tips帮助您更加容易和自动化的完成云服务器的释放和弹性设置。
11066 0
windows server 2008阿里云ECS服务器安全设置
最近我们Sinesafe安全公司在为客户使用阿里云ecs服务器做安全的过程中,发现服务器基础安全性都没有做。为了为站长们提供更加有效的安全基础解决方案,我们Sinesafe将对阿里云服务器win2008 系统进行基础安全部署实战过程! 比较重要的几部分 1.
8125 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,云吞铺子总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系统盘、创建快照、配置安全组等操作如何登录ECS云服务器控制台? 1、先登录到阿里云ECS服务器控制台 2、点击顶部的“控制台” 3、通过左侧栏,切换到“云服务器ECS”即可,如下图所示 通过ECS控制台的远程连接来登录到云服务器 阿里云ECS云服务器自带远程连接功能,使用该功能可以登录到云服务器,简单且方便,如下图:点击“远程连接”,第一次连接会自动生成6位数字密码,输入密码即可登录到云服务器上。
20973 0
+关注
行者武松
杀人者,打虎武松也。
17142
文章
2569
问答
文章排行榜
最热
最新
相关电子书
更多
《Nacos架构&原理》
立即下载
《看见新力量:二》电子书
立即下载
云上自动化运维(CloudOps)白皮书
立即下载