解析Axios原理之二:如何实现请求与响应的阻拦

作者 : 开心源码 本文共4601个字,预计阅读时间需要12分钟 发布时间: 2022-05-13 共230人阅读

Axios阻拦器在项目中所扮演的角色是非常重要的,它可以阻拦每一次的请求和响应,而后进行相应的解决。经阅读其源码,不禁被作者的神级思维所折服!简直是将Promise用到了极致!

1、公告一个用于阻拦器管理的构造函数
// 公告阻拦器管理构造函数function InterceptorManager(){    // 用于存放Axios阻拦行为及数据请求的Promise链条    this.handlers = [];}// 添加阻拦器InterceptorManager.prototype.use = function (fulfilled,rejected) {    this.handlers.push({        fulfilled,        rejected    })}
2、Axios 构造函数中添加 interceptors
function Axios(instanceConfig){    // defaults 属性为配置对象    this.defaults = instanceConfig;    // interceptors 属性用来设置请求和响应阻拦器    this.interceptors = {        request: new InterceptorManager(),        response: new InterceptorManager(),    }}
3、对之前封装好的 request 进行调整
Axios.prototype.request = function (config) {    function dispatchRequest(){        // 发送xhr请求……    }    // dispatchRequest 发送请求,undefined 用来补位    var chain = [dispatchRequest, undefined];    // 遍历实例对象的请求阻拦器    this.interceptors.request.handlers.forEach(interceptor=>{        // 将请求阻拦器压入数组的最前面        chain.unshift(interceptor.fulfilled,interceptor.rejected)    })    // 遍历实例对象的响应阻拦器    this.interceptors.response.handlers.forEach(interceptor=>{        // 将请求阻拦器压入数组的最后面        chain.push(interceptor.fulfilled,interceptor.rejected);    })    // 创立一个成功的 promise 且成功的值为合并后的请求配置    let promise = Promise.resolve(config);    // 假如链条长度不为 0    while (chain.length){        // 依次取出 chain 的回调函数, 并执行        promise = promise.then(chain.shift(),chain.shift())    }    return promise;}
4、完整代码
// 公告阻拦器管理构造函数function InterceptorManager(){    // 用于存放Axios阻拦行为及数据请求的Promise链条    this.handlers = [];}// 添加阻拦器InterceptorManager.prototype.use = function (fulfilled,rejected) {    this.handlers.push({        fulfilled,        rejected    })}function Axios(instanceConfig){    // defaults 属性为配置对象    this.defaults = instanceConfig;    // interceptors 属性用来设置请求和响应阻拦器    this.interceptors = {        request: new InterceptorManager(),        response: new InterceptorManager(),    }}Axios.prototype.request = function (config) {    function dispatchRequest(){        // 将请求方式一律转为大写        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 {a:1,b:2} a=1&b=2                // ["a","b"]                const arr = Object.keys(config.params);                // ["a=1","b=2"]                const arr2 = arr.map(v=>v+"="+config.params[v]);                // a=1&b=2                const url = arr2.join("&");                // config.url = config.url + "?" + url;                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();            }        })    }    // dispatchRequest 发送请求,undefined 用来补位    var chain = [dispatchRequest, undefined];    // 遍历实例对象的请求阻拦器    this.interceptors.request.handlers.forEach(interceptor=>{        // 将请求阻拦器压入数组的最前面        chain.unshift(interceptor.fulfilled,interceptor.rejected)    })    // 遍历实例对象的响应阻拦器    this.interceptors.response.handlers.forEach(interceptor=>{        // 将请求阻拦器压入数组的最后面        chain.push(interceptor.fulfilled,interceptor.rejected);    })    // 创立一个成功的 promise 且成功的值为合并后的请求配置    let promise = Promise.resolve(config);    // 假如链条长度不为 0    while (chain.length){        // 依次取出 chain 的回调函数, 并执行        promise = promise.then(chain.shift(),chain.shift())    }    return promise;}// axios 本质不是Axios构造函数的实例,而是一个函数对象。函数是requestfunction createInstance(defaultConfig){    const context = new Axios(defaultConfig);    Axios.prototype.request.bind(context);    // instance 是一个函数。该函数是request,并且内部this指向context.    var instance = Axios.prototype.request.bind(context);// 等同于上面那行代码    // 将Axios的原型方法放置到instance函数属性中    Object.keys(Axios.prototype).forEach(method=>{        instance[method] = Axios.prototype[method].bind(context)    })    Object.keys(context).forEach(attr=>{        instance[attr] = context[attr];    })    return instance;}export default createInstance;
5、测试
// 两个请求axios.interceptors.request.use(config=>{    console.log("request1");    return config;},error=>{    console.log("request1",error)    return Promise.reject(error);})axios.interceptors.request.use(config=>{    console.log("request2");    // throw "异常呀"    return config;},error=>{    return Promise.reject(error);})// 两个响应axios.interceptors.response.use(res=>{    console.log("response1");    return res;},error=>{    return Promise.reject(error)})axios.interceptors.response.use(res=>{    console.log("response2",res);    return res.data;},error=>{    return Promise.reject(error)})// 发送请求axios.request({    url:"data.json",    method:"post",    data:{        a:1,        b:2    }}).then(value=>{    console.log(11111,value);}).catch(err=>{    console.log(err);})
说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 解析Axios原理之二:如何实现请求与响应的阻拦

发表回复