最新公告
  • 欢迎您光临网站无忧模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • axios使用及实现

    正文概述 掘金(可乐1028)   2021-03-27   763

    axios使用及实现

    1.get

    1.1.使用

    import axios from 'axios';
    const baseUrl = 'http://localhost:8080';
    const user = {
        name: 'zhangsan',
        password: '123456'
    }
    axios({
        url:baseUrl+ '/get',
        method: 'get',
        params: user
    }).then(response => {
        console.log(response);
    }).catch(error => {
        console.log(error);
    })
    

    1.2.支持get的实现

    axios
    ├── Axios.js
    └── index.js
    
    1.2.1.axios/index.js
    import Axios from './Axios';
    function createInstance(){
        const context=new Axios();
        //让request方法里的this永远指向context也就是new Axios
        let instance=Axios.prototype.request.bind(context);
        //把Axios的类的实例和类的原型上的方法都拷贝到了instance上,也就是request方法上
        instance=Object.assign(instance,Axios.prototype,context);
        return instance;
    }
    const axios=createInstance();
    export default axios;
    
    1.2.2.axios/Axios.js
    import qs from 'qs';
    import parseHeaders from 'parse-headers';
    
    class Axios {
    
        request(config = {}) {
            return this.dispatchRequest(config);
        }
    
        dispatchRequest(config) {
            return new Promise((resolve, reject) => {
                let { url, method, params } = config;
                if (params) {//{name:'zhangsan',password:'123456'}=>name='zhangsan'&password='123456'
                    params = qs.stringify(params);
                    url = url + (url.indexOf('?') > -1 ? '&' : '?') + params;
                }
                const xhr = new XMLHttpRequest();
                //第三个参数异步
                xhr.open(method, url, true);
                //设置返回值为json
                xhr.responseType = 'json';
                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4) {
                        if (xhr.status >= 200 && xhr.status < 300) {
                            const response = {
                                data: xhr.response,
                                headers: parseHeaders(xhr.getAllResponseHeaders()),
                                status: xhr.status,
                                statusText: xhr.statusText,
                                config,
                                request: xhr
                            }
                            resolve(response);
                        } else {
                            reject('请求失败');
                        }
                    }
                }
                xhr.send();
            })
        }
    }
    
    export default Axios;
    

    2.post

    2.1.使用

    import axios from 'axios';
    const baseUrl = 'http://localhost:8080';
    const user = {
        name: 'zhangsan',
        password: '123456'
    }
    axios({
        url:baseUrl+ '/post',
        method: 'post',
        headers:{//请求头
            'Content-Type':'application/json'
        },
        data:user,//请求体
    }).then(response => {
        console.log(response);
    }).catch(error => {
        console.log(error);
    })
    

    2.2.实现

    2.2.1.修改Axios.js
    import qs from 'qs';
    import parseHeaders from 'parse-headers';
    
    class Axios {
    
        request(config = {}) {
            return this.dispatchRequest(config);
        }
    
        dispatchRequest(config) {
            return new Promise((resolve, reject) => {
    +           let { url, method = 'get', params, data, headers } = config;
                if (params) {//{name:'zhangsan',password:'123456'}=>name='zhangsan'&password='123456'
                    params = qs.stringify(params);
                    url = url + (url.indexOf('?') > -1 ? '&' : '?') + params;
                }
                const xhr = new XMLHttpRequest();
                //第三个参数异步
                xhr.open(method, url, true);
                //设置返回值为json
                xhr.responseType = 'json';
                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4) {
                        if (xhr.status >= 200 && xhr.status < 300) {
                            const response = {
                                data: xhr.response,
                                headers: parseHeaders(xhr.getAllResponseHeaders()),
                                status: xhr.status,
                                statusText: xhr.statusText,
                                config,
                                request: xhr
                            }
                            resolve(response);
                        } else {
                            reject('请求失败');
                        }
                    }
                }
    
                //请求头的处理
    +           if (headers) {
    +               Object.keys(headers).forEach(key => {
    +                   xhr.setRequestHeader(key, headers[key]);
    +               })
    +           }
    
                //请求体的处理
    +           let body = null;
    +           if (typeof data === 'object' && data !== null) {
    +               body = JSON.stringify(data);//转化为字符串
    +           }
    +           xhr.send(body);
            })
        }
    }
    
    export default Axios;
    

    3.错误处理

    • 请求超时
    • 网络异常
    • 状态码错误

    3.1.实例

    3.1.1.请求超时
    axios({
        url: baseUrl + '/post_timeout?timeout=3000',
        method: 'post',
        headers: {
            'Content-Type': 'application/json'
        },
        data: user,
    +   timeout: 1000
    }).then(response => {
        console.log(response);
    }).catch(error => {
        console.log(error);
    })
    
    3.1.2.网络异常
    + setTimeout(() => {
        axios({
            url: baseUrl + '/post',
            method: 'post',
            headers: {
                'Content-Type': 'application/json'
            },
            data: user
        }).then(response => {
            console.log(response);
        }).catch(error => {
            console.log(error);
        })
    + }, 3000);
    
    3.1.3.状态码错误
    axios({
        url: baseUrl + '/post_status?code=300',
        method: 'post',
        headers: {
            'Content-Type': 'application/json'
        },
        data: user,
        timeout:1000,
    }).then(response => {
        console.log(response);
    }).catch(error => {
        console.log(error);
    })
    

    3.2.实现

    3.2.1.Axios.js修改
    import qs from 'qs';
    import parseHeaders from 'parse-headers';
    
    class Axios {
    
        request(config = {}) {
            return this.dispatchRequest(config);
        }
    
        dispatchRequest(config) {
            return new Promise((resolve, reject) => {
    +       let { url, method = 'get', params, data, headers,timeout } = config;
                if (params) {//{name:'zhangsan',password:'123456'}=>name='zhangsan'&password='123456'
                    params = qs.stringify(params);
                    url = url + (url.indexOf('?') > -1 ? '&' : '?') + params;
                }
                const xhr = new XMLHttpRequest();
                //第三个参数异步
                xhr.open(method, url, true);
                //设置返回值为json
                xhr.responseType = 'json';
                xhr.onreadystatechange = function () {
    +                if (xhr.readyState === 4 && xhr.status !==0) {
                       if (xhr.status >= 200 && xhr.status <300) {
                            const response = {
                                data: xhr.response,
                                headers: parseHeaders(xhr.getAllResponseHeaders()),
                                status: xhr.status,
                                statusText: xhr.statusText,
                                config,
                                request: xhr
                            }
                            resolve(response);
                        } else {
     +                      reject(new Error(`Error: Request failed with status code ${xhr.status}`))
                        }
                    }
                }
    
                //请求头的处理
                if (headers) {
                    Object.keys(headers).forEach(key => {
                        xhr.setRequestHeader(key, headers[key]);
                    })
                }
    
                //请求体的处理
                let body = null;
                if (typeof data === 'object' && data !== null) {
                    body = JSON.stringify(data);//转化为字符串
                }
    
                //超时异常
    +           if(timeout){
    +               xhr.timeout=timeout;//设置超时时间
    +               xhr.ontimeout=function(){//超时监听
    +                   reject(new Error(`Error: timeout of ${timeout}ms exceeded`));
    +               }
    +           }
    
                //网络异常
    +           xhr.onerror=function(){
    +               reject(new Error(`net::ERR_INTERNET_DISCONNECTED`));
    +           }
    
                xhr.send(body);
            })
        }
    }
    
    export default Axios;
    

    4.拦截器

    • axios请求拦截器是插入后执行,响应拦截器是先插入先执行
    • interceptors.request.use:使用请求拦截器
      • use(onFulfilled?: (value: AxiosRequestConfig) => AxiosRequestConfig | Promise<AxiosRequestConfig>, onRejected?: (error: any) => any): number
      • use回调有两个可选参数:onFulfilledonRejected
      • onFulfilled执行返回值可能是AxiosRequestConfig|Promise<AxiosRequestConfig>,use执行返回值是当前位置,便于eject取消
    • interceptors.response.use:使用响应拦截器
      • use(onFulfilled?: (value: AxiosResponse<any>) => AxiosResponse<any> | Promise<AxiosResponse<any>>, onRejected?: (error: any) => any): number
      • use回调有两个可选参数:onFulfilledonRejected
      • onFulfilled执行返回值可能是AxiosResponse<any>|Promise<AxiosResponse<any>>,,use执行返回值是当前位置,便于eject取消
    • interceptors.request.eject:取消请求使用的某个拦截器
    • interceptors.response.eject:取消响应使用的某个拦截器

    4.1.使用

    import axios from 'axios';
    const baseUrl = 'http://localhost:8080';
    const user = {
        name: 'zhangsan',
        password: '123456'
    }
    
    //请求拦截
    +axios.interceptors.request.use((config) => {
    +   config.headers.name += '1';
    +   return config;
    +})
    +const request_interceptor = axios.interceptors.request.use((config) => {
    +   config.headers.name += '2';
    +   return config;
    +})
    +axios.interceptors.request.use((config) => {
    +   config.headers.name += '3';
    +   return config;
    +})
    +axios.interceptors.request.eject(request_interceptor);//取消某个请求拦截器
    
    
    //响应拦截
    +axios.interceptors.response.use(response => {
    +   response.data.name += '1';
    +   return response;
    +})
    +const response_intereptor = axios.interceptors.response.use(response => {
    +   response.data.name += '2';
    +   return response;
    +})
    +axios.interceptors.response.use(response => {
    +   response.data.name += '3';
    +   return response;
    +})
    +axios.interceptors.response.eject(response_intereptor);//取消某个设置的影响拦截器
    
    axios({
        url: baseUrl + '/post',
        method: 'post',
        headers: {
            'Content-Type': 'application/json',
    +       'name':'lisi'
        },
        data: user,
        timeout: 1000,
    }).then(response => {
        console.log(response.data);
    }).catch(error => {
        console.log(error);
    })
    
    4.1.1.请求分析

    axios使用及实现

    4.1.2.响应分析

    axios使用及实现

    4.2.实现

    axios
    ├── Axios.js
    ├── AxiosInterceptorManager.js
    └── index.js
    
    4.2.1.AxiosInterceptorManager.js拦截器管理者
    class AxiosInterceptorManager{
        constructor(){
            this.interceptors=[];
        }
        //注册拦截器
        use(onFulfilled,onRejected){
            this.interceptors.push({
                onFulfilled,
                onRejected
            })
            return this.interceptors.length-1;//返回当前注册的位置
        }
        //取消拦截器
        eject(interceptorIndex){
            if(this.interceptors[interceptorIndex]){
                this.interceptors[interceptorIndex]=null;
            }
        }
    }
    export default AxiosInterceptorManager;
    
    4.2.2.Axios.js修改
    import qs from 'qs';
    import parseHeaders from 'parse-headers';
    + import AxiosInterceptorManager from './AxiosInterceptorManager';
    class Axios {
    
    +   constructor() {
    +       this.interceptors = {
    +           request: new AxiosInterceptorManager(),//请求拦截器的管理者
    +           response: new AxiosInterceptorManager()//响应拦截器的管理者
    +       };
    +   }
    
        request(config = {}) {
     +      const chain = [{//设置真正发请求的,然后将请求拦截出入前面,响应拦截插入后面,实现现走请求拦截,再发请求,最后响应拦截
     +          onFulfilled: this.dispatchRequest,
     +          onRejected: undefined
     +      }];
            //将请求拦截器一个一个插入最前面,实现先放的后执行
     +      this.interceptors.request.interceptors.forEach(interceptor => {
     +          interceptor && chain.unshift(interceptor);
     +      })
            //将响应拦截一个个查处末尾,实现先放先执行
     +      this.interceptors.response.interceptors.forEach(interceptor => {
     +          interceptor && chain.push(interceptor);
     +      })
     +      let promise = Promise.resolve(config);
     +      while (chain.length) {
     +          const { onFulfilled, onRejected } = chain.shift();//取出每次的第一条数据
                //将config传入onFulfilled
     +          promise = promise.then(onFulfilled, onRejected);
     +      }
     +      return promise;
     +  }
    
        dispatchRequest(config) {
            return new Promise((resolve, reject) => {
                let { url, method = 'get', params, data, headers, timeout } = config;
                if (params) {//{name:'zhangsan',password:'123456'}=>name='zhangsan'&password='123456'
                    params = qs.stringify(params);
                    url = url + (url.indexOf('?') > -1 ? '&' : '?') + params;
                }
                const xhr = new XMLHttpRequest();
                //第三个参数异步
                xhr.open(method, url, true);
                //设置返回值为json
                xhr.responseType = 'json';
                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4 && xhr.status !==0) {
                        if (xhr.status >= 200 && xhr.status < 300) {
                            const response = {
                                data: xhr.response,
                                headers: parseHeaders(xhr.getAllResponseHeaders()),
                                status: xhr.status,
                                statusText: xhr.statusText,
                                config,
                                request: xhr
                            }
                            resolve(response);
                        } else {
                            reject(new Error(`Error: Request failed with status code ${xhr.status}`))
                        }
                    }
                }
    
                //请求头的处理
                if (headers) {
                    Object.keys(headers).forEach(key => {
                        xhr.setRequestHeader(key, headers[key]);
                    })
                }
    
                //请求体的处理
                let body = null;
                if (typeof data === 'object' && data !== null) {
                    body = JSON.stringify(data);//转化为字符串
                }
    
                //超时异常
                if (timeout) {
                    xhr.timeout = timeout;//设置超时时间
                    xhr.ontimeout = function () {//超时监听
                        reject(new Error(`Error: timeout of ${timeout}ms exceeded`));
                    }
                }
    
                //网络异常
                xhr.onerror = function () {
                    reject(new Error(`net::ERR_INTERNET_DISCONNECTED`));
                }
    
                xhr.send(body);
            })
        }
    }
    
    export default Axios;
    

    5.合并配置

    5.1.使用:

    axios({
        url: baseUrl + '/post',
        method: 'post',
        headers: {
            'name': 'lisi',
        },
        data: user,
        timeout: 1000,
    }).then(response => {
        console.log(response.data);
    }).catch(error => {
        console.log(error);
    })
    

    axios使用及实现

    5.2.实现

    import qs from 'qs';
    import parseHeaders from 'parse-headers';
    import AxiosInterceptorManager from './AxiosInterceptorManager';
    
    //默认配置
    +const defaults = {
    +   method: 'get',
    +   timeout: 0,
    +   headers: {
    +       common: {
    +           accept: 'application/json'//指定告诉服务器返回JSON格式的数据
    +       }
    +   }
    +}
    +const getStyleMethods = ['get', 'head', 'delete', 'options'];//get风格的请求
    +getStyleMethods.forEach(method => {
    +   defaults.headers[method] = {}
    +})
    
    +const postStyleMethods = ['put', 'post', 'patch'];//post风格的请求,会有请求体,需要加默认请求体格式
    +postStyleMethods.forEach(method => {
    +   defaults.headers[method] = {
    +       'content-type':'application/json'//请求体格式
    +   }
    +})
    
    +const allMethods = [...getStyleMethods, ...postStyleMethods];
    
    class Axios {
    
        constructor() {
    +       this.defaults = defaults;
            this.interceptors = {
                request: new AxiosInterceptorManager(),//请求拦截器的管理者
                response: new AxiosInterceptorManager()//响应拦截器的管理者
            };
        }
    
        request(config = {}) {
            //合并默认配置headers和用户自己配置headers
    +       config.headers = Object.assign(this.defaults.headers, config.headers);
    
            const chain = [{//设置真正发请求的,然后将请求拦截出入前面,响应拦截插入后面,实现现走请求拦截,再发请求,最后响应拦截
                onFulfilled: this.dispatchRequest,
                onRejected: undefined
            }];
            //将请求拦截器一个一个插入最前面,实现先放的后执行
            this.interceptors.request.interceptors.forEach(interceptor => {
                interceptor && chain.unshift(interceptor);
            })
            //将响应拦截一个个查处末尾,实现先放先执行
            this.interceptors.response.interceptors.forEach(interceptor => {
                interceptor && chain.push(interceptor);
            })
            let promise = Promise.resolve(config);
            while (chain.length) {
                const { onFulfilled, onRejected } = chain.shift();//取出每次的第一条数据
                //将config传入onFulfilled
                promise = promise.then(onFulfilled, onRejected);
            }
            return promise;
        }
    
        dispatchRequest(config) {
            return new Promise((resolve, reject) => {
                let { url, method = 'get', params, data, headers, timeout } = config;
                if (params) {//{name:'zhangsan',password:'123456'}=>name='zhangsan'&password='123456'
                    params = qs.stringify(params);
                    url = url + (url.indexOf('?') > -1 ? '&' : '?') + params;
                }
                const xhr = new XMLHttpRequest();
                //第三个参数异步i,
                xhr.open(method, url, true);
                //设置返回值为json
                xhr.responseType = 'json';
                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4  && xhr.status !==0) {
                        if (xhr.status >= 200 && xhr.status < 300) {
                            const response = {
                                data: xhr.response,
                                headers: parseHeaders(xhr.getAllResponseHeaders()),
                                status: xhr.status,
                                statusText: xhr.statusText,
                                config,
                                request: xhr
                            }
                            resolve(response);
                        } else {
                            reject(new Error(`Error: Request failed with status code ${xhr.status}`))
                        }
                    }
                }
    
                //请求头的处理
                if (headers) {
                    /**
                     * headers:{
                     *   common:{accept: 'application/json'},
                     *   post:{'content-type':'application/json'}
                     * }
                     */
    +               Object.keys(headers).forEach(key => {
    +                   if (key === 'common' || allMethods.includes(key)) {
    +                       if (key === 'common' || key === config.method) {
    +                           Object.keys(headers[key]).forEach(key2 => {
    +                               xhr.setRequestHeader(key2, headers[key][key2]);
    +                           })
    +                       }
    +                   } else {
    +                       xhr.setRequestHeader(key, headers[key]);
    +                   }
    +               })
    +           }
    
                //请求体的处理
                let body = null;
                if (typeof data === 'object' && data !== null) {
                    body = JSON.stringify(data);//转化为字符串
                }
    
                //超时异常
                if (timeout) {
                    xhr.timeout = timeout;//设置超时时间
                    xhr.ontimeout = function () {//超时监听
                        reject(new Error(`Error: timeout of ${timeout}ms exceeded`));
                    }
                }
    
                //网络异常
                xhr.onerror = function () {
                    reject(new Error(`net::ERR_INTERNET_DISCONNECTED`));
                }
    
                xhr.send(body);
            })
        }
    }
    
    export default Axios;
    

    6.转换请求与响应

    6.1.Axios.js修改

    import qs from 'qs';
    import parseHeaders from 'parse-headers';
    import AxiosInterceptorManager from './AxiosInterceptorManager';
    
    //默认配置
    const defaults = {
        method: 'get',
        timeout: 0,
        headers: {
            common: {
                accept: 'application/json'//指定告诉服务器返回JSON格式的数据
            }
        },
    +   transformRequest: function (data, headers) {
    +       headers['content-type'] = 'application/x-www-form-urlencoded';
    +       return qs.stringify(data);
    +   },
    +   transformResponse: function (data) {
    +       if (typeof data === 'string');
    +       data = JSON.parse(data);
    +       return data;
    +   }
    }
    const getStyleMethods = ['get', 'head', 'delete', 'options'];//get风格的请求
    getStyleMethods.forEach(method => {
        defaults.headers[method] = {}
    })
    
    const postStyleMethods = ['put', 'post', 'patch'];//post风格的请求,会有请求体,需要加默认请求体格式
    postStyleMethods.forEach(method => {
        defaults.headers[method] = {
            'content-type': 'application/json'//请求体格式
        }
    })
    
    const allMethods = [...getStyleMethods, ...postStyleMethods];
    
    class Axios {
    
        constructor() {
            this.defaults = defaults;
            this.interceptors = {
                request: new AxiosInterceptorManager(),//请求拦截器的管理者
                response: new AxiosInterceptorManager()//响应拦截器的管理者
            };
        }
    
        request(config = {}) {
            //合并默认配置headers和用户自己配置headers
            config.headers = Object.assign(this.defaults.headers, config.headers);
            //如果有请求转换,执行
    +       if (config.transformRequest && config.data) {
    +           config.data = config.transformRequest(config.data, config.headers);
    +       }
            const chain = [{//设置真正发请求的,然后将请求拦截出入前面,响应拦截插入后面,实现现走请求拦截,再发请求,最后响应拦截
                onFulfilled: this.dispatchRequest,
                onRejected: undefined
            }];
            //将请求拦截器一个一个插入最前面,实现先放的后执行
            this.interceptors.request.interceptors.forEach(interceptor => {
                interceptor && chain.unshift(interceptor);
            })
            //将响应拦截一个个查处末尾,实现先放先执行
            this.interceptors.response.interceptors.forEach(interceptor => {
                interceptor && chain.push(interceptor);
            })
            let promise = Promise.resolve(config);
            while (chain.length) {
                const { onFulfilled, onRejected } = chain.shift();//取出每次的第一条数据
                //将config传入onFulfilled
                promise = promise.then(onFulfilled, onRejected);
            }
            return promise;
        }
    
        dispatchRequest(config) {
            return new Promise((resolve, reject) => {
                let { url, method = 'get', params, data, headers, timeout } = config;
                if (params) {//{name:'zhangsan',password:'123456'}=>name='zhangsan'&password='123456'
                    params = qs.stringify(params);
                    url = url + (url.indexOf('?') > -1 ? '&' : '?') + params;
                }
                const xhr = new XMLHttpRequest();
                //第三个参数异步i,
                xhr.open(method, url, true);
                //设置返回值为json
                xhr.responseType = 'json';
                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4 && xhr.status !==0) {
                        if (xhr.status >= 200 && xhr.status < 300) {
                            let response = {
                                data: xhr.response,
                                headers: parseHeaders(xhr.getAllResponseHeaders()),
                                status: xhr.status,
                                statusText: xhr.statusText,
                                config,
                                request: xhr
                            }
                            //响应转换
    +                       if (config.transformResponse) {
    +                           response = config.transformResponse(response);
    +                       }
                            resolve(response);
                        } else {
                            reject(new Error(`Error: Request failed with status code ${xhr.status}`))
                        }
                    }
                }
    
                //请求头的处理
                if (headers) {
                    /**
                     * headers:{
                     *   common:{accept: 'application/json'},
                     *   post:{'content-type':'application/json'}
                     * }
                     */
                    Object.keys(headers).forEach(key => {
                        if (key === 'common' || allMethods.includes(key)) {
                            if (key === 'common' || key === config.method) {
                                Object.keys(headers[key]).forEach(key2 => {
                                    xhr.setRequestHeader(key2, headers[key][key2]);
                                })
                            }
                        } else {
                            xhr.setRequestHeader(key, headers[key]);
                        }
                    })
                }
    
                //请求体的处理
                let body = null;
                if (typeof data === 'object' && data !== null) {
                    body = JSON.stringify(data);//转化为字符串
                }
    
                //超时异常
                if (timeout) {
                    xhr.timeout = timeout;//设置超时时间
                    xhr.ontimeout = function () {//超时监听
                        reject(new Error(`Error: timeout of ${timeout}ms exceeded`));
                    }
                }
    
                //网络异常
                xhr.onerror = function () {
                    reject(new Error(`net::ERR_INTERNET_DISCONNECTED`));
                }
    
                xhr.send(body);
            })
        }
    }
    
    export default Axios;
    

    7.取消任务

    • isCancel:判断是否是用户自己取得任务
    • CancelToken:是一个类,source方法返回一个对象,包含tokencancel
    • cancel:取消任务

    7.1.实例

    axios使用及实现

    import axios from 'axios';
    const baseUrl = 'http://localhost:8080';
    const user = {
        name: 'zhangsan',
        password: '123456'
    }
    
    const CancelToken = axios.CancelToken;
    const source = CancelToken.source();
    const isCancel = axios.isCancel;
    axios({
        url: baseUrl + '/post',
        method: 'post',
        headers: {
            'name': 'lisi',
        },
        data: user,
        timeout: 1000,
        cancelToken: source.token
    }).then(response => {
        console.log(response.data);
    }).catch(error => {
        if (isCancel(error)) {
            console.log('用户自己' + error)
        } else {
            console.log(error);
        }
    })
    
    source.cancel('取消请求')
    

    7.2.实现

    axios
    ├── Axios.js
    ├── AxiosInterceptorManager.js
    ├── cancel.js
    └── index.js
    
    7.2.1.cancel.js
    export class Cancel {
        constructor(reason) {
            //存放取消的原因
            this.reason = reason;
        }
    }
    export class CancelToken {
        constructor() {
            this.resolve = null;
        }
        source() {
            return {
                token: new Promise(resolve => {
                    this.resolve = resolve;
                }),
                cancel: reason => {
                    this.resolve(new Cancel(reason))
                }
            }
        }
    }
    
    //判断error是不是Cancel的实例
    export function isCancel(error) {
        return error instanceof Cancel;
    }
    
    7.2.2.index.js修改
        import Axios from './Axios';
    +   import { CancelToken, isCancel } from './cancel';
        function createInstance() {
            const context = new Axios();
            //让request方法里的this永远指向context也就是new Axios
            let instance = Axios.prototype.request.bind(context);
            //把Axios的类的实例和类的原型上的方法都拷贝到了instance上,也就是request方法上
            instance = Object.assign(instance, Axios.prototype, context);
            return instance;
        }
        const axios = createInstance();
    +   axios.CancelToken = new CancelToken();
    +   axios.isCancel = isCancel;
        export default axios;
    
    7.2.3.Axios.js修改
    import qs from 'qs';
    import parseHeaders from 'parse-headers';
    import AxiosInterceptorManager from './AxiosInterceptorManager';
    
    //默认配置
    const defaults = {
        method: 'get',
        timeout: 0,
        headers: {
            common: {
                accept: 'application/json'//指定告诉服务器返回JSON格式的数据
            }
        },
        transformRequest: function (data, headers) {
            headers['content-type'] = 'application/x-www-form-urlencoded';
            return qs.stringify(data);
        },
        transformResponse: function (data) {
            if (typeof data === 'string');
            data = JSON.parse(data);
            return data;
        }
    }
    const getStyleMethods = ['get', 'head', 'delete', 'options'];//get风格的请求
    getStyleMethods.forEach(method => {
        defaults.headers[method] = {}
    })
    
    const postStyleMethods = ['put', 'post', 'patch'];//post风格的请求,会有请求体,需要加默认请求体格式
    postStyleMethods.forEach(method => {
        defaults.headers[method] = {
            'content-type': 'application/json'//请求体格式
        }
    })
    
    const allMethods = [...getStyleMethods, ...postStyleMethods];
    
    class Axios {
    
        constructor() {
            this.defaults = defaults;
            this.interceptors = {
                request: new AxiosInterceptorManager(),//请求拦截器的管理者
                response: new AxiosInterceptorManager()//响应拦截器的管理者
            };
        }
    
        request(config = {}) {
            //合并默认配置headers和用户自己配置headers
            config.headers = Object.assign(this.defaults.headers, config.headers);
            //如果有请求转换,执行
            if (config.transformRequest && config.data) {
                config.data = config.transformRequest(config.data, config.headers);
            }
            const chain = [{//设置真正发请求的,然后将请求拦截出入前面,响应拦截插入后面,实现现走请求拦截,再发请求,最后响应拦截
                onFulfilled: this.dispatchRequest,
                onRejected: undefined
            }];
            //将请求拦截器一个一个插入最前面,实现先放的后执行
            this.interceptors.request.interceptors.forEach(interceptor => {
                interceptor && chain.unshift(interceptor);
            })
            //将响应拦截一个个查处末尾,实现先放先执行
            this.interceptors.response.interceptors.forEach(interceptor => {
                interceptor && chain.push(interceptor);
            })
            let promise = Promise.resolve(config);
            while (chain.length) {
                const { onFulfilled, onRejected } = chain.shift();//取出每次的第一条数据
                //将config传入onFulfilled
                promise = promise.then(onFulfilled, onRejected);
            }
            return promise;
        }
    
        dispatchRequest(config) {
            return new Promise((resolve, reject) => {
                let { url, method = 'get', params, data, headers, timeout } = config;
                if (params) {//{name:'zhangsan',password:'123456'}=>name='zhangsan'&password='123456'
                    params = qs.stringify(params);
                    url = url + (url.indexOf('?') > -1 ? '&' : '?') + params;
                }
                const xhr = new XMLHttpRequest();
                //第三个参数异步i,
                xhr.open(method, url, true);
                //设置返回值为json
                xhr.responseType = 'json';
                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4 && xhr.status !== 0) {
                        if (xhr.status >= 200 && xhr.status < 300) {
                            let response = {
                                data: xhr.response,
                                headers: parseHeaders(xhr.getAllResponseHeaders()),
                                status: xhr.status,
                                statusText: xhr.statusText,
                                config,
                                request: xhr
                            }
                            debugger
                            //响应转换
                            if (config.transformResponse) {
                                response = config.transformResponse(response);
                            }
                            resolve(response);
                        } else {
                            reject(new Error(`Error: Request failed with status code ${xhr.status}`))
                        }
                    }
                }
    
                //请求头的处理
                if (headers) {
                    /**
                     * headers:{
                     *   common:{accept: 'application/json'},
                     *   post:{'content-type':'application/json'}
                     * }
                     */
                    Object.keys(headers).forEach(key => {
                        if (key === 'common' || allMethods.includes(key)) {
                            if (key === 'common' || key === config.method) {
                                Object.keys(headers[key]).forEach(key2 => {
                                    xhr.setRequestHeader(key2, headers[key][key2]);
                                })
                            }
                        } else {
                            xhr.setRequestHeader(key, headers[key]);
                        }
                    })
                }
    
                //请求体的处理
                let body = null;
                if (typeof data === 'object' && data !== null) {
                    body = JSON.stringify(data);//转化为字符串
                }
    
                //超时异常
                if (timeout) {
                    xhr.timeout = timeout;//设置超时时间
                    xhr.ontimeout = function () {//超时监听
                        reject(new Error(`Error: timeout of ${timeout}ms exceeded`));
                    }
                }
    
                //网络异常
                xhr.onerror = function () {
                    reject(new Error(`net::ERR_INTERNET_DISCONNECTED`));
                }
    
                //处理用户自己取消的操作
    +           if (config.cancelToken) {
    +               config.cancelToken.then(reason => {
    +                   xhr.abort();//取消请求
    +                   reject(reason);
    +               })
    +           }
                xhr.send(body);
            })
        }
    }
    
    export default Axios;
    

    下载网 » axios使用及实现

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元