解析Axios原理之二:如何实现请求与响应的阻拦
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原理之二:如何实现请求与响应的阻拦
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 解析Axios原理之二:如何实现请求与响应的阻拦