Axios

Axios

1. Axios 简介

Axios 是一个基于 promise 网络请求库,作用于 node.js 和浏览器中。 它是 isomorphic 的(同一套代码可以运行在浏览器和 node.js 中)。在服务端它使用原生 node.js http 模块,而在客户端则使用 XMLHttpRequest。

2. 特性

  • 从浏览器创建 XMLHttpRequests
  • 从 node.js 创建 http 请求;
  • 支持 Promise API;
  • 拦截请求和响应;
  • 转换请求和响应数据;
  • 取消请求;
  • 自动转换 JSON 数据;
  • 客户端支持防御 XSRF

3. 封装 Axios

由于 axios 是一个基于 xhr+promise 的异步 ajax 请求库,所以可以先单纯的封装一个:

function axios(config){
    // 将请求方式全部转为大写
    const method = (config.method || "get").toUpperCase();
    // 返回 Promise
    return new Promise((resolve,reject) => {
        // 声明 xhr
        const xhr = new XMLHttpRequest();
        // 定义一个 onreadystatechange 监听事件
        xhr.onreadystatechange = function () {
            // 数据全部加载完成
            if(xhr.readyState === 4){
                // 判断状态码是否正确
                if(xhr.status >= 200 && xhr.status < 300){
                    // 得到响应体的内容
                    const data = JSON.parse(xhr.responseText);
                    // 得到响应头
                    const headers = xhr.getAllResponseHeaders();
                    // request 即是 xhr
                    const request = xhr;
                    // 状态码
                    const status = xhr.status;
                    // 状态码的说明
                    const statusText = xhr.statusText;
                    resolve({
                        config,
                        data,
                        headers,
                        request,
                        status,
                        statusText
                    });
                }
                else{
                    reject("请求失败" + xhr.status + xhr.statusText);
                }
            }
        }
        // 判断是否拥有 params, 且类型为 object
        if(typeof config.params === "object"){
            // 将 object 转为 urlencoded 
            const arr = Object.keys(config.params);
            const arr2 = arr.map(v => v + "=" + config.params[v]);
            const url = arr2.join("&");
            config.url +=  "?" + url;
        }
        xhr.open(method, config.url);
        // post put patch
        if(method === "POST" || method === "PUT" || method === "PATCH"){
            if(typeof config.data === "object")
                xhr.setRequestHeader("content-type", "application/json");
            else if(typeof config.data === "string")
                xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");
            xhr.send(JSON.stringify(config.data));
        }
        else{
            xhr.send();
        }
    })
}

以上代码实现了 axios(config) 直接发起请求,例如:

axios({
    method: "delete",
    url: "data.json"
}).then(res => console.log(res))

但是,如果想通过 axios.get(url[, config])、axios.delete(url[, config])、axios.post(url[, data[, config]]) 等请求方式就行不通了。

4. 封装 request

通过阅读源码得到一些启示:源码中有一个名为 Axios 的构造函数,而我们的 xhr + promise 封装在 Axios.prototype.request 函数中。另外所使用的 axios.get、axios.post 等也都是定义在 Axios.prototype 中。

根据这些启示将代码调整为:

// 构造函数
function Axios(){

}
Axios.prototype.request = function (config) {
    // 将请求方式全部转为大写
    const method = (config.method || "get").toUpperCase();
    // 返回Promise
    return new Promise((resolve,reject)=>{
        // 声明xhr
        const xhr = new XMLHttpRequest();
        // 定义一个onreadystatechange监听事件
        xhr.onreadystatechange = function () {
            // 数据全部加载完成
            if(xhr.readyState === 4){
                // 判断状态码是否正确
                if(xhr.status >= 200 && xhr.status < 300){
                    // 得到响应体的内容
                    const data = JSON.parse(xhr.responseText);
                    // 得到响应头
                    const headers = xhr.getAllResponseHeaders();
                    // request 即是 xhr
                    const request = xhr;
                    // 状态码
                    const status = xhr.status;
                    // 状态码的说明
                    const statusText = xhr.statusText;
                    resolve({ 
                        config, 
                        data, 
                        headers, 
                        request, 
                        status, 
                        statusText 
                    });
                }
                else{
                    reject("请求失败" + xhr.status + xhr.statusText);
                }
            }
        }
        // http://127.0.0.1/two?a=1&b=2
        // 判断是否拥有 params, 且类型为 object
        if(typeof config.params === "object"){
            // 将 object 转为 urlencoded 
            const arr = Object.keys(config.params);
            const arr2 = arr.map(v => v + "=" + config.params[v]);
            const url = arr2.join("&");
            config.url +=  "?" + url;
        }
        xhr.open(method,config.url);
        // post put patch
        if(method === "POST" || method === "PUT" || method === "PATCH"){
            if(typeof config.data === "object")
                xhr.setRequestHeader("content-type","application/json");
            else if(typeof config.data === "string")
                xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");
            xhr.send(JSON.stringify(config.data));
        }
        else{
            xhr.send();
        }
    })
}
Axios.prototype.get = function (url, config) {
    return this.request({
        method: "get",
        url,
        ...config
    });
}
Axios.prototype.post = function (url, data) {
    return this.request({
        url,
        method: "post",
        data
    })
}
// 其它请求 delete, patch 省略
export default new Axios();

这样可以通过 axios.get(url[, config])、axios.post(url[, data[, config]]) 请求数据了。

import axios from "./Axios.js";
axios.post("data.json", {
    a:1,
    b:2
}).then(res=>{
    console.log(res);
})
axios.get("data.json",{
    params:{
        a:1,
        b:2
    }
}).then(res=>{
    console.log(res);
})

计算机网络 文章被收录于专栏

计算机网络

全部评论

相关推荐

喜欢吃蛋糕仰泳鲈鱼是我的神:字节可以找个hr 给你挂了,再放池子捞
点赞 评论 收藏
分享
一个菜鸡罢了:哥们,感觉你的简历还是有点问题的,我提几点建议,看看能不能提供一点帮助 1. ”新余学院“别加粗,课程不清楚是否有必要写,感觉版面不如拿来写一下做过的事情,教育经历是你的弱势就尽量少写 2. “干部及社团经历”和“自我评价”删掉 3. 论文后面的“录用”和“小修”啥的都删掉,默认全录用,问了再说,反正小修毕业前肯定能发出来 4. 工作经验和研究成果没有体现你的个人贡献,着重包装一下个人贡献
点赞 评论 收藏
分享
评论
1
收藏
分享
牛客网
牛客企业服务