【封装原生ajax请求】也没那么复杂嘛!

1. 何为Ajax请求?

ajax请求技术是一种异步请求技术,可以让浏览器在无需重新刷新页面的情况下,通过ajax向后台发送请求并等后台数据响应后呈现在页面上。
也可以说,ajax请求就是通过原生的XMLHttpRequest对象发出的HTTP请求,得到服务器返回的数据后,异步渲染在页面上。

2. Ajax请求步骤

ajax请求的流程是:

  • 浏览器给xhr对象说去服务器请求一些数据
  • 然后浏览器自身并不会因为xhr对象去和服务器进行交互而处于阻塞的状况,而是会继续执行页面,此时xhr会去向服务器发送请求
  • 等到xhr对象从服务器获取了数据后,会通知给浏览器,从而将xhr对象从服务器上获取到的数据渲染在页面上
  • 整个过程都不需要刷新页面,因此称为异步

ajax的核心是xhr(XMLHttpRequest),使用xhr发送ajax请求的步骤为:

  • 创建XMLHttpRequest实例
  • 发送HTTP实例
  • 监听请求
  • 接收服务器返回的数据
  • 异步渲染数据至页面

jQuery中,封装了ajax作为网络请求的接口,那么我们就先来看看在jQuery中,是如何调用ajax来发送请求的吧:

$.ajax({
    url: 'XXX',
    type: 'get',
    data: {
        id: 1,
        name: '张三'
    },
    dataType: 'json', 
    success: function (res) {
        console.log(res);
    }
});

通过上述调用ajax的结构,基本上可以归纳出:
ajax请求接收一个对象作为参数,该对象内包含进行网络请求时需要的url地址,type,请求参数,成功之后的回调函数等...
了解了ajax请求的步骤后,我们就来自己上手封装一个ajax吧~

2.1 第一步 生成默认参数

ajax请求应包含请求的URLcontentTypesuccessasync标识等基本信息。
用户在调用ajax请求时不必填写每一项,可以只填写url这种最基本的信息,以及根据需求决定是否需要传递其他参数。

  • 如果用户没有传递某些参数,ajax就应该直接使用默认的值
  • 如果用户传递了一些参数,就应该用传递进来的新值来替换默认值中对应的属性值
function ajax(opt) {
    // 设置一些默认参数
    let defaultParam = {
        url: '#',
        type: 'GET',
        data: {},
        contentType: 'application/json',
        async: false,
        success: function () {},
        error: function () {}
    }
    // 用传递进来的新值来替换默认的属性值
    for (let key in opt) {
        defaultParam[key] = opt[key];
    }
}

2.2 第二步 创建XMLHttpRequest实例

为了考虑不同浏览器之间的兼容性,我们需要根据当前浏览器是否包含XMLHttpRequest对象来分别处理。
我们在前一个代码的基础上进一步完善:

function ajax(opt) {
    // 第一步:设置一些默认参数
    let defaultParam = {
        url: '#',
        type: 'GET',
        data: {},
        contentType: 'application/json',
        async: false,
        success: function () {},
        error: function () {}
    }
    // 用传递进来的新值来替换默认的属性值
    for (let key in opt) {
        defaultParam[key] = opt[key];
    }
    // 第二步:声明xhr对象
    let xhr = null;
    if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest();
    } else {
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
    }
}

2.3 打开请求(发送HTTP实例)

当声明了xhr对象后,我们就可以着手打开请求和发送请求的工作了。
打开请求这一步需要xhr对象的open方法和send方法。 同时,对于不同的请求type需要分别处理。
本文就简要处理GETPOST两种请求。
考虑到请求里可能需要携带参数,因此我们需要提前处理一下接收进来的data

function ajax(opt) {
    // 第一步:设置一些默认参数
    let defaultParam = {
        url: '#',
        type: 'GET',
        data: {},
        contentType: 'application/json',
        async: false,
        success: function () {},
        error: function () {}
    }
    // 用传递进来的新值来替换默认的属性值
    for (let key in opt) {
        defaultParam[key] = opt[key];
    }
    // 处理参数格式备用
    let paramStr = ''
    for (let k in defaultParam.data) {
        paramStr += k + '=' + defaultParam.data[k] + '&';
    }
    paramStr = paramStr.substr(0, paramStr.length - 1);
    // 第二步:声明xhr对象
    let xhr = null;
    if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest();
    } else {
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
    }
    
}

接下来,我们可以先写一下请求TypeGET的请求:
GET相比于POST请求来说,就简单多了,发送请求通过调用opensend两个方法 。 open()函数里接收三个参数:

  • 第一个参数是请求类型
  • 第二个参数是请求url,如果有携带参数,就直接拼接在url中即可
  • 第三个参数是请求是否异步

send()函数里不需要携带参数。

function ajax(opt) {
    // 第一步:设置一些默认参数
    let defaultParam = {
        url: '#',
        type: 'GET',
        data: {},
        contentType: 'application/json',
        async: false,
        success: function () {},
        error: function () {}
    }
    // 用传递进来的新值来替换默认的属性值
    for (let key in opt) {
        defaultParam[key] = opt[key];
    }
    // 处理参数格式备用
    let paramStr = ''
    for (let k in defaultParam.data) {
        paramStr += k + '=' + defaultParam.data[k] + '&';
    }
    paramStr = paramStr.substr(0, paramStr.length - 1);
    // 第二步:声明xhr对象
    let xhr = null;
    if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest();
    } else {
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
    }
    // 第三步:发送请求
    if (defaultParam.type === 'GET') {
        xhr.open(defaultParam.type, defaultParam.url + "?" + paramStr, defaultParam.async);
        xhr.send();
    }
}

接下来,我们来完善POST请求:
POST请求相比于GET请求的复杂之处在于:

扫描二维码关注公众号,回复: 14354215 查看本文章
  • data参数需要单独传递,不能拼接在url
  • 需要根据contentType设置请求头(因为不同的请求头,请求携带的参数格式不同)

如果contentTypeapplication/json,那么传递的参数需要使用JSON.stringify方法把data转换为字符串传递给后台。
如果contentTypeapplication/x-www-form-urlencoded,那么就直接传递我们之前处理好的paramStr即可。
代码如下:

function ajax(opt) {
    // 第一步:设置一些默认参数
    let defaultParam = {
        url: '#',
        type: 'GET',
        data: {},
        contentType: 'application/json',
        async: false,
        success: function () {},
        error: function () {}
    }
    // 用传递进来的新值来替换默认的属性值
    for (let key in opt) {
        defaultParam[key] = opt[key];
    }
    // 处理参数格式备用
    let paramStr = ''
    for (let k in defaultParam.data) {
        paramStr += k + '=' + defaultParam.data[k] + '&';
    }
    paramStr = paramStr.substr(0, paramStr.length - 1);
    // 第二步:声明xhr对象
    let xhr = null;
    if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest();
    } else {
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
    }
    // 第三步:发送请求,使用switch比if更优雅
    if (defaultParam.type === 'GET') {
        xhr.open(defaultParam.type, defaultParam.url + "?" + paramStr, defaultParam.async);
        xhr.send();
    } else {
        xhr.open(defaultParam.type, defaultParam.url, defaultParam.async);
        if (defaultParam.contentType === 'application/json') {
            xhr.setRequestHeader('Content-Type', 'application/json');
            xhr.send(JSON.stringify(dafaultParam.data));//调用ajax时传递进来的参数
        } else if (defaultParam.contentType === 'application/x-www-form-urlencoded') {
            // 设置请求类型为formData
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            xhr.send(paramStr);//调用ajax时传递进来的参数,
        }

    }
}

2.4 监听请求

当我们发送完请求后,剩下的工作就是监听请求了:

  • 调用xhr.onreadystatechange方法来监听请求
  • 调用xhr.readyState来监听请求进度
    • readyState === 0时,表明【未初始化】,还没有调用send()方法
    • readyState === 1时,表明【载入】,已调用send()方法,正在发送请求
    • readyState === 2时,表明【载入完成】,send()执行完成,已经接收到全部的响应内容
    • readyState === 3时,表明【交互】,正在解析响应内容
    • readyState === 4时,表明【完成】,响应内容解析完成,可以在客户端调用了
  • 调用xhr.status来获取服务器响应的状态码
    • 1XX:信息性状态码     ,表示接收的请求正在处理
    • 2XX:成功状态码       , 表示请求正常处理
    • 3XX:重定向状态码    ,表示需要附加操作来完成请求
    • 4XX:客户端错误状态  ,表示服务器无法处理请求
    • 5XX:服务器错误状态  ,表示服务器处理请求出错

如果readyState === 4 && status === 200,就代表请求发送成功,并且服务器端进行了正确的处理,此时客户端就可以根据服务器返回的数据进行下一步操作了。如果status等于其他状态码,我们就需要处理异常,告诉客户端本次请求发送失败。
xhr.responseText里存储着服务端返回给客户端的数据,该数据是JSON格式的字符串,为了便于回调函数更方便的使用这些数据,我们需要使用JSON.parse把它转换成JSON格式,然后作为参数传递给success这个回调函数,供其他组件使用。
完整代码如下:

function ajax(opt) {
    // 第一步:设置一些默认参数
    let defaultParam = {
        url: '#',
        type: 'GET',
        data: {},
        contentType: 'application/json',
        async: false,
        success: function () {},
        error: function () {}
    }
    // 用传递进来的新值来替换默认的属性值
    for (let key in opt) {
        defaultParam[key] = opt[key];
    }
    // 处理参数格式备用
    let paramStr = ''
    for (let k in defaultParam.data) {
        paramStr += k + '=' + defaultParam.data[k] + '&';
    }
    paramStr = paramStr.substr(0, paramStr.length - 1);
    // 第二步:声明xhr对象
    let xhr = null;
    if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest();
    } else {
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
    }
    // 第三步:发送请求,使用switch比if更优雅
    if (defaultParam.type === 'GET') {
        xhr.open(defaultParam.type, defaultParam.url + "?" + paramStr, defaultParam.async);
        xhr.send();
    } else {
        xhr.open(defaultParam.type, defaultParam.url, defaultParam.async);
        if (defaultParam.contentType === 'application/json') {
            xhr.setRequestHeader('Content-Type', 'application/json');
            xhr.send(JSON.stringify(dafaultParam.data));//调用ajax时传递进来的参数
        } else if (defaultParam.contentType === 'application/x-www-form-urlencoded') {
            // 设置请求类型为formData
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            xhr.send(paramStr);//调用ajax时传递进来的参数,
        }

    }
    // 第四步:监听请求
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                let res = JSON.parse(xhr.responseText);
                defaultParam.success(res);
            }
        }
    }
}

至此,我们就完成了一个简易版原生Ajax的封装,又多了一项前端技能呢~

猜你喜欢

转载自juejin.im/post/7110448203614388254