UNPKG

fet-block

Version:

fetBlock is a web h5 request hook library

7 lines (6 loc) 6.08 kB
/*! * fet-block v1.0.0 * (c) sheldon cui * Released under the MIT License. */ !function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";let e=function(t){return e=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__},e(t)};const t=function(){let t=window.XMLHttpRequest.prototype;for(;t&&e(t)!==XMLHttpRequestEventTarget.prototype;)t=e(t);return t.constructor}();async function s(e){return new Promise((s=>{const r=new t;r.openUrl=e.url,r.open(e.method||"get",e.url),r.timeout=e.timeout||5e3,r.responseType=e.responseType||"text",r.onload=function(){"text"===r.responseType?s({status:r.status,statusText:r.statusText,body:r.responseText,headers:r.getAllResponseHeaders()}):s(r.response)},r.onerror=function(e){reject(new Error("network error"))},r.ontimeout=function(e){reject(new Error("network timeout"))},r.send()}))}function r(e){if(/^([a-z]+:)?\/\//i.test(e))return e;const t=new URL(window.location.href),s=t.origin+t.pathname;return new URL(e,s).toString()}function n(){const e=navigator.userAgent,t=/Android/.test(e),s=/iPhone|iPad|iPod/.test(e);return{isAndroid:t,isIOS:s,isWeixin:/MicroMessenger/.test(e),isQQ:/QQ/.test(e),isPC:!t&&!s,lang:window.navigator.language}}async function o(e,t){if("sendRequestByJsBridge"===t)return function(e){return s(e)}(e)}function i(...e){var t,s;(t=window.location.href,s="fetblock_debug",function(e){const t=e.split("#")[0].split("?")[1]||"",s={};return t.split("&").forEach((e=>{const[t,r]=e.split("=");s[t]=r})),s}(t)[s])&&console.warn(...e)}let a="/dist/config.json";window.fetBlockConfigUrl&&(a=window.fetBlockConfigUrl);const u="fet_block_config_json";let h=!0;const p={originConfig:{},userProperty:{},finalRules:{}};async function d(){i("init rulesManager");const e=function(e){try{const t=localStorage.getItem(e);if(t)return JSON.parse(t)}catch(e){return null}}(u);if(e&&(p.originConfig=e),p.userProperty={lang:n().lang},p.finalRules=function(e,t){const s=e[t.lang];for(const e in s)s[e]&&"string"==typeof s[e]&&(s[e]=[s[e]]);return s}(p.originConfig,p.userProperty)||{},window.FET_BLOCK_CONFIG=p,h){h=!1;const e=await s({url:a});localStorage.setItem(u,e?.body),d()}}function l(e,t){const s=function(e){const{url:t="",method:s="get",headers:n={},body:o}=e,i={};for(const e in n)i[e.toLowerCase()]=n[e];return{url:r(t),method:s.toLowerCase(),headers:i||{},body:o}}(e),{finalRules:n}=p,o=function(e){try{return new URL(e).hostname}catch(e){return""}}(s?.url),i=n[o];if(!i)return{type:"xhr",targetUrl:s?.url};let a=null;for(const e of i){if(["sendRequestByJsBridge"].includes(e)){if("sendRequestByJsBridge"!==e||t)continue;a={type:"tunnel",targetUrl:s?.url,tunnelApi:e}}else a={type:"xhr",targetUrl:s?.url?.replace(o,e)};return a}}class c extends window.XMLHttpRequest{static isFetBlockXHR=!0;static fetBlockVersion="1.0.0";#e=0;#t="";#s=0;#r="";#n={};#o="";#i="";#a=!1;#u={};#h=null;constructor(){super()}get status(){return"xhr"!==this.#i?this.#e:super.status}get statusText(){return"xhr"!==this.#i?this.#t:super.statusText}get readyState(){return"xhr"!==this.#i?this.#s:super.readyState}get responseText(){return"xhr"!==this.#i?this.#r:super.responseText}get responseHeaders(){return"xhr"!==this.#i?this.#n:super.responseHeaders}get responseURL(){return"xhr"!==this.#i?this.#o:super.responseURL}get response(){return"xhr"!==this.#i?"json"===this.responseType?JSON.parse(this.#r):this.#r:super.response}open(e,t,s=!0,r,n){if(this.#p(),!e||!t)throw new Error("method and url are required");super.open(e,t,s,r,n),this.#h={method:e,url:t,async:s,username:r,password:n},this.#s=1}send(e){const t=l(this.#h);if(i("最佳规则为:",t),!t)return super.send();if(this.#i=t.type,"tunnel"!==this.#i)return super.open(this.#h.method,t.targetUrl,this.#h.async,this.#h.username,this.#h.password),Object.keys(this.#u).forEach((e=>{super.setRequestHeader(e,this.#u[e])})),super.send(e);const s=t.tunnelApi,r=o({...this.#h,url:t.targetUrl,body:e},s);this.dispatchEvent(new ProgressEvent("loadstart",{loaded:0,total:0})),r.then((e=>{if(this.#a)return;let s=0,r=100;"object"==typeof e&&e?.body&&"string"==typeof e?.body&&(s=e?.body?.length,r=e?.body?.length),this.dispatchEvent(new ProgressEvent("progress",{loaded:s,total:r})),this.#s=4,this.#e=e.status||200,this.#t=e.statusText||"TUNNEL_REQUEST_OK",this.#n=e?.headers||{},this.#r=e?.body,this.#o=t.targetUrl,this.dispatchEvent(new ProgressEvent("readystatechange")),this.dispatchEvent(new ProgressEvent("load",{loaded:e?.body?.length,total:e?.body?.length})),i("xhr内部onload触发完成")})).catch((e=>{if(!this.#a)return this.#p({status:0,statusText:"",readyState:4}),this.#r="",this.#n={},this.#o="",this.dispatchEvent(new ProgressEvent("error",{loaded:0,total:0})),this.dispatchEvent(new ProgressEvent("loadend",{loaded:0,total:0})),e})).then((e=>{if(this.#a)return;let t=0,s=100;"object"==typeof e&&e?.body&&"string"==typeof e?.body&&(t=e?.body?.length,s=e?.body?.length),this.dispatchEvent(new ProgressEvent("loadend",{loaded:t,total:s}))})),this.#s=2,this.dispatchEvent(new Event("readystatechange"))}getAllResponseHeaders(){return"xhr"!==this.#i?getResponseHeadersStr(this.#n):super.getAllResponseHeaders()}getResponseHeader(e){return"xhr"!==this.#i?this.#n[e]:super.getResponseHeader(e)}setRequestHeader(e,t){this.#u[e]=t,super.setRequestHeader(e,t)}abort(){this.#a=!0,super.abort(),this.#p({isAbort:!0}),"xhr"!==this.#i&&Promise.resolve().then((()=>{this.dispatchEvent(new ProgressEvent("abort",{loaded:0,total:0}))}))}#p(e={}){const{readyState:t,status:s,statusText:r,isAbort:n}=e;this.#e=s||0,this.#t=r,this.#s=t||0,this.#u={},this.#r="",this.#n={},this.#o="",this.#i="xhr",this.#a="boolean"==typeof n&&n}}function g(e){const t=l({url:e},!0);return t?t.targetUrl:e}function f(){i("init hookmanager"),window.XMLHttpRequest?.isFetBlockXHR||(window.XMLHttpRequest=c),i("hook xhr"),function(){if(!window.fetch)return;const e=window.fetch;window.fetch=function(t,...s){return"string"==typeof t?e.call(this,g(t),...s):e.call(this,t,...s)}}(),i("hook fetch")}window._isInitFetBlock||(d(),f(),window._isInitFetBlock=!0)}));