ajax 源码分析

发布时间 2023-08-04 10:25:10作者: monkey-K
/**
  源码来源:https://github.com/wendux/Ajax-hook * XHR属性方法: * Type Function: [abort,getAllResponseHeaders,getResponseHeader,open,overrideMimeType,send,setRequestHeader] * type object: [onreadystatechange,upload,responseXML,onprogress,onabort,onloadstart,onload,onloadend,onerror,ontimeout] * type number: [readyState,timeout,UNSENT,OPENED,HEADERS_RECEIVED,LOADING,DONE] * type string: [statusText,responseType,response,responseText] *
*/ const ORIGINXHR = '__origin__'; export function hook(proxy: any, win?: typeof globalThis) { win = win || window; // 1. 缓存原始的 XMLHttpRequest 对象 let originXhr = win.XMLHttpRequest // @ts-ignore win.XMLHttpRequest = function () { let xhr: any = new originXhr(); for (let attr in xhr) { // @ts-ignore let type = typeof xhr[attr]; // 3. 处理方法:函数类型的注入hooks,重写方法, if (type === "function") { // console.log("attr==type: function=>", type, attr) this[attr] = useHookFunction(attr); } // 4. 处理属性:非函数类型的添加get set, 忽略保存到原始对象。 this.__origin__.toString() == "[object XMLHttpRequest]" // this 指向新的XHR对象 else if (attr !== ORIGINXHR) { // console.log("attr==type: !function=>", type, attr) Object.defineProperty(this, attr, { get: getterFactory(attr), set: setterFactory(attr), enumerable: true // 确保能被for in 循环 }) } } this[ORIGINXHR] = xhr; // console.log(this, "hook XMLHttpRequest") } function useHookFunction(fun: string) { return function () { let args = [].slice.call(arguments); if (proxy[fun]) { let ret = proxy[fun].call(this, args, this[ORIGINXHR]) if (ret) return ret; } return this[ORIGINXHR][fun].apply(this[ORIGINXHR], args); } } function getterFactory(attr: any) { return function () { let v = this.hasOwnProperty(attr + "_") ? this[attr + "_"] : this[ORIGINXHR][attr]; return v; // let attrGetterHook = (proxy[attr] || {})["getter"]; // return attrGetterHook && attrGetterHook(v, this) || v; } } function setterFactory(attr: string) { console.log("all == attr", attr) return function (v: any) { let xhr = this[ORIGINXHR]; // 原始 XHR let that = this; // 新 XHR let hook = proxy[attr]; // 传入的 hook func // 1. 处理的事件: onloadend,onerror,ontimeout if (attr.startsWith('on')) { console.log("on == attr", attr) that[attr + "_"] = v; console.log("setterFactory", v, proxy[attr]) xhr[attr] = function (e: any) { e = configEvent(e, that) let ret = proxy[attr] && proxy[attr].call(that, xhr, e) // 1. 原始XHR上执行传入的hook事件(方法) console.log("ret", ret) ret || v.call(that, e); // 2.新的XHR上执行外部定义的事件回调 } } // 2. 处理其他属性 else { // 普通属性拦截器写法 // hook( // //需要拦截的属性名 // timeout: { // //拦截写操作 // setter: function (v, xhr) { // //超时最短为1s,返回值为最终值。 // return Math.max(v, 1000); // } // } // ) // let attrSetterHook = (hook || {})["setter"]; // 源码这个写法有问题,修改为如下: let attrSetterHook = hook["setter"] || null; console.log("un event:", attr, attrSetterHook) v = attrSetterHook && attrSetterHook(v, that) || v // 替换普通属性为拦截器的值 this[attr + "_"] = v; // 新的xhr对象上复制属性 try { xhr[attr] = v; // 原始xhr对象赋值属性 } catch (e) { } } } } function unHook() { win!.XMLHttpRequest = originXhr; // @ts-ignore originXhr = undefined; } return { originXhr, unHook } } export function configEvent(event:Event, xhrProxy: any) { let e: any = {}; for (let attr in event) { // @ts-ignore e[attr] = event[attr]; } e.target = e.currentTarget = xhrProxy return e; }