Skip to content

Axios

Axios类实例

js
//Axios类的配置信息
function Axios(config){
    this.defaults = config
    this.interceptors={
        request:new InterceptorManager(),
        response:new InterceptorManager()
    }
}
//用于创建axios
function createInstance(config){
    //创建一个Axios实例
    let context=new Axios(config)
    //将Axios原型链上的request方法指向Axios实例,为了后续的方法调用
    let instance=Axios.prototype.request.bind(context)
    //将Axios原型链上的所有方法指向Axios实例,然后浅拷贝给instatnce,因此instance具备Axios原型链上的所有方法
    Object.keys(Axios.prototype).forEach(item=>{
        instance[item]=Axios.prototype[item].bind(context)
    })
    // 将Axios实例上所有配置信息拷贝给instance,instance现在是具备Axios实例上所有配置信息以及原型链上的所有方法
    Object.keys(context).forEach(item=>{
        instance[item]=context[item]
    })
    //疑问:为什么不直接instance=new Axios(config),这样直接可以拿到配置项和原型链上的方法
    //主要还是因为axios还有一些自有的配置项,比如axios.cancelToken,axios.create,axios.all等方法
    //封装Axios主要用于接口请求
    return instance
}

示例

js
// 创建 axios 函数
//创建实例
let axios = createInstance()

//创建axios实例
axios.create = function create(instanceConfig) {
    return createInstance(Object.assign({},axios.defaults, instanceConfig));
};
const duanzi = axios.create({
    baseURL: 'http://localhost:3000/posts/2',
    timeout: 2000
});

Axios拦截器

js
//拦截器管理器 存放拦截器数组
function InterceptorManager(){
    this.handlers=[]
}
InterceptorManager.prototype.use=function use(fulfilled,rejected) {
    // 将所有拦截器都储存在这个拦截器数组中
    this.handlers.push({fulfilled,rejected})
    //返回拦截器的编号
    return this.handlers.length-1
}
//get方法
Axios.prototype.get=function (url,config){
    return this.request({
        url,
        method:'get',
        ...config
    })
}
//post方法
Axios.prototype.post=function (url,config){
    return this.request({
        url,
        method:'post',
        ...config
    })
}
//Axois原型链上的方法  Axios调用的所有方法默认都是底层调用request方法
Axios.prototype.request=function (config){
    console.log('发送请求的方式是:',config.method)
    //创建一个Promise对象是为了递归处理数据
    let promise=Promise.resolve(config)
    // dispatchRequest是调用适配器函数,用于处理接口调用的返回值,undefined是占位符,保证请求加拦截器都能成对输出
    let chains=[dispatchRequest,undefined]
    // 将请求拦截器的数组放在chains数组前面待处理
    this.interceptors.request.handlers.forEach(item=>{
        chains.unshift(item.fulfilled,item.rejected)
    })
    //将响应拦截器的数组放在chains数组后面待处理
    this.interceptors.response.handlers.forEach(item=>{
        chains.push(item.fulfilled,item.rejected)
    })
    //while循环chains数组,处理所有请求拦截器,请求和响应拦截器
    while (chains.length>0){
        promise=promise.then(chains.shift(),chains.shift())
    }
    //promise.then可以递归处理数据
    return promise
}
//dispatchRequest函数是用于调用适配器方法来进行接口调用的
function dispatchRequest(config){
    //xhrAapter是适配器函数
    return xhrAapter(config).then(response=>{
        //成功返回值
        return response
    }).catch(error=>{
        //失败返回值
        return error
    })
}

示例

js
//获取按钮
const btns = document.querySelectorAll('button');
// 设置请求拦截器  config 配置对象
axios.interceptors.request.use(function one(config) {
    console.log('请求拦截器 成功 - 1号');
    return config;
}, function one(error) {
    console.log('请求拦截器 失败 - 1号');
    return Promise.reject(error);
});

axios.interceptors.request.use(function two(config) {
    console.log('请求拦截器 成功 - 2号');
    return config;
}, function two(error) {
    console.log('请求拦截器 失败 - 2号');
    return Promise.reject(error);
});

// 设置响应拦截器
axios.interceptors.response.use(function (response) {
    console.log('响应拦截器 成功 1号');
    return response;
}, function (error) {
    console.log('响应拦截器 失败 1号')
    return Promise.reject(error);
});

axios.interceptors.response.use(function (response) {
    console.log('响应拦截器 成功 2号')
    return response;
}, function (error) {
    console.log('响应拦截器 失败 2号')
    return Promise.reject(error);
});


//请求拦截器 成功 - 2号
//请求拦截器 成功 - 1号
//响应拦截器 成功 1号
//响应拦截器 成功 2号

Axios取消请求

js
function xhrAapter(config){
    console.log('适配器函数')
    let requestData = config.data;
    //适配器函数返回一个Prosmise对象,便于处理接口返回值
    return new Promise((resolve, reject)=>{
        //ajax底层原理    创建xhrHttpRequest对象
        let xhr=new XMLHttpRequest();
        // 设置请求头
        // xhr.setRequestHeader('Content-Type', 'application/json')
        //开启一个请求
        xhr.open(config.method, config.url,true);
        //发送请求并附带请求参数
        xhr.send(JSON.stringify(requestData))
        //监听请求方法
        xhr.onreadystatechange=function () {
            //成功请求状态判断
            if(xhr.readyState===4){
                //成功状态
                if(xhr.status >= 200 && xhr.status < 300){
                    resolve({
                        //配置对象
                        config: config,
                        //响应体
                        data: xhr.response,
                        //响应头
                        headers: xhr.getAllResponseHeaders(), //字符串  parseHeaders
                        // xhr 请求对象
                        request: xhr,
                        //响应状态码
                        status: xhr.status,
                        //响应状态字符串
                        statusText: xhr.statusText
                    })
                }else{
                    //失败的状态
                    reject(new Error('请求失败 失败的状态码为' + xhr.status));
                }
            }
        }
        // 取消请求的处理
        if(config.cancelToken){
            //config.cancelToken.promise是一个promise对象
            config.cancelToken.promise.then(cancel=>{
                xhr.abort()
                //将整体结果设置为失败
                reject(new Error('请求已经被取消'))
            })
        }
    })
}
//CancelToken构造函数
function  CancelToken(executor){
    // 声明promise对象变量
    var resolvePromise
    //为CancelToken构造函数添加实例,实例里面是promise对象
    this.promise=new Promise(resolve=>{
        //存储resolve状态
        resolvePromise=resolve
    })
    executor(function () {
        //直接执行promise并让其成功
        resolvePromise()
    })
}

示例

js
<div class="container">
    <h2 class="page-header">基本使用</h2>
    <button class="btn btn-primary"> 发送GET请求 </button>
    <button class="btn btn-warning" > 发送POST请求 </button>
    <button class="btn btn-success"> 发送 PUT 请求 </button>
    <button class="btn btn-danger"> 发送 DELETE 请求 </button>
    <button class="btn btn-primary"> 发送请求 </button>
    <button class="btn btn-warning"> 取消请求 </button>
</div>
//第一个
btns[0].onclick = function(){
    //发送 AJAX 请求
    duanzi({
        //请求类型
        method: 'GET',
        //URL
        url: ``,
    }).then(response => {
        console.log(response);
    });
}

//添加一篇新的文章
btns[1].onclick = function(){
    //发送 AJAX 请求
    axios({
        //请求类型
        method: 'POST',
        //URL
        url: 'http://localhost:3000/posts',
        //设置请求体
        data: {
            title: "今天天气不错, 还挺风和日丽的",
            author: "张三"
        }
    }).then(response => {
        console.log(response);
    });
}

//更新数据
btns[2].onclick = function(){
    //发送 AJAX 请求
    axios({
        //请求类型
        method: 'PUT',
        //URL
        url: 'http://localhost:3000/posts/3',
        //设置请求体
        data: {
            title: "今天天气不错, 还挺风和日丽的",
            author: "李四"
        }
    }).then(response => {
        console.log(response);
    });
}

//删除数据
btns[3].onclick = function(){
    //发送 AJAX 请求
    axios({
        //请求类型
        method: 'delete',
        //URL
        url: 'http://localhost:3000/posts/3',
    }).then(response => {
        console.log(response);
    });
}
//删除数据
let cancel=null
btns[4].onclick = function(){
    console.log('11111')
    //cancel不为空说明正在请求接口,直接阻止请求
    if(cancel!==null){
        cancel()
    }
    //创建cancelToken值
    let cancelToken=new CancelToken(function(c){
        cancel=c
    })
    //发送 AJAX 请求
    axios({
        //请求类型
        method: 'POST',
        //URL
        url: 'http://localhost:3000/posts',
        //设置请求体
        data: {
            title: "今天天气不错, 还挺风和日丽的",
            author: "张三"
        },
        //可以阻止请求的参数
        cancelToken:cancelToken
    }).then(response => {
        console.log(response);
        //请求结束,阻止请求参数赋值为null
        cancel=null
    });
}
btns[5].onclick = function(){
    cancel()
}

Axios实现源码

js
//Axios类的配置信息
function Axios(config){
    this.defaults = config
    this.interceptors={
        request:new InterceptorManager(),
        response:new InterceptorManager()
    }
}
//拦截器管理器 存放拦截器数组
function InterceptorManager(){
    this.handlers=[]
}
InterceptorManager.prototype.use=function use(fulfilled,rejected) {
    // 将所有拦截器都储存在这个拦截器数组中
    this.handlers.push({fulfilled,rejected})
    //返回拦截器的编号
    return this.handlers.length-1
}
//Axois原型链上的方法  Axios调用的所有方法默认都是底层调用request方法
Axios.prototype.request=function (config){
    console.log('发送请求的方式是:',config.method)
    //创建一个Promise对象是为了递归处理数据
    let promise=Promise.resolve(config)
    // dispatchRequest是调用适配器函数,用于处理接口调用的返回值,undefined是占位符,保证请求加拦截器都能成对输出
    let chains=[dispatchRequest,undefined]
    // 将请求拦截器的数组放在chains数组前面待处理
    this.interceptors.request.handlers.forEach(item=>{
        chains.unshift(item.fulfilled,item.rejected)
    })
    //将响应拦截器的数组放在chains数组后面待处理
    this.interceptors.response.handlers.forEach(item=>{
        chains.push(item.fulfilled,item.rejected)
    })
    //while循环chains数组,处理所有请求拦截器,请求和响应拦截器
    while (chains.length>0){
        promise=promise.then(chains.shift(),chains.shift())
    }
    //promise.then可以递归处理数据
    return promise
}
//dispatchRequest函数是用于调用适配器方法来进行接口调用的
function dispatchRequest(config){
    //xhrAapter是适配器函数
    return xhrAapter(config).then(response=>{
        //成功返回值
        return response
    }).catch(error=>{
        //失败返回值
        return error
    })
}
function xhrAapter(config){
    console.log('适配器函数')
    let requestData = config.data;
    //适配器函数返回一个Prosmise对象,便于处理接口返回值
    return new Promise((resolve, reject)=>{
        //ajax底层原理    创建xhrHttpRequest对象
        let xhr=new XMLHttpRequest();
        // 设置请求头
        // xhr.setRequestHeader('Content-Type', 'application/json')
        //开启一个请求
        xhr.open(config.method, config.url,true);
        //发送请求并附带请求参数
        xhr.send(JSON.stringify(requestData))
        //监听请求方法
        xhr.onreadystatechange=function () {
            //成功请求状态判断
            if(xhr.readyState===4){
                //成功状态
                if(xhr.status >= 200 && xhr.status < 300){
                    resolve({
                        //配置对象
                        config: config,
                        //响应体
                        data: xhr.response,
                        //响应头
                        headers: xhr.getAllResponseHeaders(), //字符串  parseHeaders
                        // xhr 请求对象
                        request: xhr,
                        //响应状态码
                        status: xhr.status,
                        //响应状态字符串
                        statusText: xhr.statusText
                    })
                }else{
                    //失败的状态
                    reject(new Error('请求失败 失败的状态码为' + xhr.status));
                }
            }
        }
        // 取消请求的处理
        if(config.cancelToken){
            //config.cancelToken.promise是一个promise对象
            config.cancelToken.promise.then(cancel=>{
                xhr.abort()
                //将整体结果设置为失败
                reject(new Error('请求已经被取消'))
            })
        }
    })
}
//CancelToken构造函数
function  CancelToken(executor){
    // 声明promise对象变量
    var resolvePromise
    //为CancelToken构造函数添加实例,实例里面是promise对象
    this.promise=new Promise(resolve=>{
        //存储resolve状态
        resolvePromise=resolve
    })
    executor(function () {
        //直接执行promise并让其成功
        resolvePromise()
    })
}
//get方法
Axios.prototype.get=function (url,config){
    return this.request({
        url,
        method:'get',
        ...config
    })
}
//post方法
Axios.prototype.post=function (url,config){
    return this.request({
        url,
        method:'post',
        ...config
    })
}
//用于创建axios
function createInstance(config){
    //创建一个Axios实例
    let context=new Axios(config)
    //将Axios原型链上的request方法指向Axios实例,为了后续的方法调用
    let instance=Axios.prototype.request.bind(context)
    //将Axios原型链上的所有方法指向Axios实例,然后浅拷贝给instatnce,因此instance具备Axios原型链上的所有方法
    Object.keys(Axios.prototype).forEach(item=>{
        instance[item]=Axios.prototype[item].bind(context)
    })
    // 将Axios实例上所有配置信息拷贝给instance,instance现在是具备Axios实例上所有配置信息以及原型链上的所有方法
    Object.keys(context).forEach(item=>{
        instance[item]=context[item]
    })
    //疑问:为什么不直接instance=new Axios(config),这样直接可以拿到配置项和原型链上的方法
    //主要还是因为axios还有一些自有的配置项,比如axios.cancelToken,axios.create,axios.all等方法
    //封装Axios主要用于接口请求
    return instance
}
/*
var axios=createInstance(config)
export default axios*/