@ng1005/chrome-extension-common
Version:
chrome扩展通用库--消息与storage
332 lines (323 loc) • 11.6 kB
text/typescript
export const listenerKey='_ajaxProxyInstance_listener_'
export const receiveKey='_ajaxProxyInstance_receive_'
export const script=`
const _ajaxProxyInstance = {
oriXhr: window.XMLHttpRequest,
oriFetch: window.fetch.bind(window),
listenerKey:'_ajaxProxyInstance_listener_',
receiveKey:'_ajaxProxyInstance_receive_',
interceptor:{
request:{handler:[],use:(func)=>{if (func && typeof func === 'function'){_ajaxProxyInstance.interceptor.request.handler.push(func)}}},
response:{handler:[],use:(func)=>{if (func && typeof func === 'function'){_ajaxProxyInstance.interceptor.response.handler.push(func)}}}
},
xhr: function () {
const isObjectOrArray=(source)=>{
var type = Object.prototype.toString.call(source);
var res = type === '[object Array]' || type === '[object Object]';
return res;
}
//转换为json
const toJson=(str)=>{
let json=str
try{
json=JSON.parse(str)
}catch(e){
}
return json
}
//请求参数
let req={url:'',method:'GET',headers:{},data:{}}
const xhr = new _ajaxProxyInstance.oriXhr;
const handler=_ajaxProxyInstance.interceptor.request.handler
const processHandler=()=>{
for (let i = 0; i < handler.length; ++i) {
req=handler[i].call(this, req,_ajaxProxyInstance.xhr)
}
return req;
}
const oriXhr = new _ajaxProxyInstance.oriXhr;
for (const property in oriXhr) {
if (property === 'onreadystatechange') {
oriXhr.onreadystatechange = (...args) => {
// 下载成功
if (this.readyState === 4) {
// console.log('ajax response----',req.url,xhr.responseText)
//axios请求参数---需要重写的参数
let options={
url:req.url,
method:req.method,
data:req.data,
headers:req.headers,
status: xhr.status,
statusText: '',
response:xhr.response,
responseHeaders: xhr.responseHeaders,//响应时返回响应header
}
if (xhr.status === 200&&xhr.responseText){// 判断是否有success方法并执行
const resContentType=xhr.getResponseHeader("Content-Type")
if(resContentType.includes('application/json')){
//将json字符串转换为json对象
options.response=toJson(xhr.responseText)
}
}
//拦截处理
let handlers=_ajaxProxyInstance.interceptor.response.handler
for(let i=0;i<handlers.length;i++){
options=handlers[i].call(this, options,_ajaxProxyInstance.xhr)
}
//重写结果
xhr.responseText=isObjectOrArray(options.response)?JSON.stringify(options.response):options.response
xhr.response=isObjectOrArray(options.response)?JSON.stringify(options.response):options.response
}
this.onreadystatechange && this.onreadystatechange.apply(this, args);
}
this.onreadystatechange = null;
continue;
} else if (property === 'onload') {
} else if (property === 'open') {
this.open = (...args) => {
const [method, url] = args;
req.url=url
req.method=method
//处理拦截器
req=processHandler()
//重写请求
args[0]=req.method
args[1]=req.url
oriXhr.open && oriXhr.open.apply(oriXhr, args);
}
continue;
} else if (property === 'setRequestHeader') {
this.setRequestHeader = (...args) => {
let header={[args[0]]: args[1]}
req.headers=Object.assign(req.headers,header)
//处理拦截器
req=processHandler()
//重写请求---默认最后一个加入的key为当前key
let keys=Object.keys(req.headers)
args[0]=keys[keys.length-1]
args[1]=req.headers[args[0]]
oriXhr.setRequestHeader && oriXhr.setRequestHeader.apply(oriXhr, args);
}
continue;
} else if (property === 'send') {
this.send = (...args) => {
//发送数据
if(!['get','put',''].includes(req.method.toLocaleLowerCase())){
let body=args[0]
req.data=body&&isObjectOrArray(body)?body:toJson(body)
//处理拦截器
req=processHandler()
//重写请求---数据
args[0]=req.data||arg[0]
}
oriXhr.send && oriXhr.send.apply(oriXhr, args);
}
continue;
}
if (typeof oriXhr[property] === 'function') {
this[property] = oriXhr[property].bind(oriXhr);
} else {
// responseText和response不是writeable的,但拦截时需要修改它,所以修改就存储在this[\``+'_${property}'+`\`]上
if (['responseText', 'response', 'status'].includes(property)) {
Object.defineProperty(this, property, {
get: () => this[\``+'_${property}'+`\`] == undefined ? oriXhr[property] : this[\``+'_${property}'+`\`],
set: (val) => this[\``+'_${property}'+`\`] = val,
enumerable: true
});
} else {
Object.defineProperty(this, property, {
get: () => oriXhr[property],
set: (val) => oriXhr[property] = val,
enumerable: true
});
}
}
}
},
fetch: function (...args) {
const isObjectOrArray=(source)=>{
var type = Object.prototype.toString.call(source);
var res = type === '[object Array]' || type === '[object Object]';
return res;
}
//转换为json
const toJson=(str)=>{
let json=str
try{
json=JSON.parse(str)
}catch(e){
}
return json
}
let [url,opts]=args
let req={
url,
method:opts?.method,
data:!opts?.body||isObjectOrArray(opts?.body)?opts?.body:toJson(opts?.body),
headers:opts?.headers,
}
const processHandler=(handler,...args)=>{
for (let i = 0; i < handler.length; ++i) {
req=handler[i].call(this, req,_ajaxProxyInstance.fetch)
}
args[0]=req.url||args[0]
if(!opts){
opts={}
}
opts['method']=req.method||opts?.method
opts['body']=req.data||opts?.body
opts['body']=isObjectOrArray(opts['body'])?JSON.stringify(opts['body']):opts['body']
opts['headers']=req.headers||opts?.headers
args[1]=opts;
return args
}
const getBody = async (stream) => {
let text = '';
const decoder = new TextDecoder('utf-8');
const reader = stream.getReader();
const processData = (result) => {
if (result.done) {
return text;
}
const value = result.value; // Uint8Array
text += decoder.decode(value, {stream: true});
// 读取下一个文件片段,重复处理步骤
return reader.read().then(processData);
};
return await reader.read().then(processData);
}
args=processHandler(_ajaxProxyInstance.interceptor.request.handler,...args)
return _ajaxProxyInstance.oriFetch(...args).then(async (response) => {
let handler=_ajaxProxyInstance.interceptor.response.handler
if(handler.length>0){
//默认body都返回json
let body=await getBody(response.body)
body=isObjectOrArray(body)?body:toJson(body)
//axios请求参数---需要重写的参数
let options={
url,
method:req?.method||'GET',
data:req?.data||{},
headers:req?.headers||{},
status: response.status,
statusText: response.statusText,
response:body,
responseHeaders: response.headers||opts.headers,//响应时返回响应header
}
// console.log('ajax fetch response----',options.url)
//重写返回状态与返回文本/json
for (let i = 0; i < handler.length; ++i) {
options=handler[i].call(this, options,response,_ajaxProxyInstance.fetch)
}
//重新组装成Response
let streamBody=isObjectOrArray(options.response)?JSON.stringify(options.response):options.response
const stream = new ReadableStream({
start(controller) {
controller.enqueue(new TextEncoder().encode(streamBody));
controller.close();
}
});
const newResponse = new Response(stream, {
headers: options.headers||response.headers,
status: options.status||response.status,
statusText: options.statusText||response.statusText,
});
//生成代理对象
const responseProxy = new Proxy(newResponse, {
get: function (target, name) {
switch (name) {
case 'body':
case 'bodyUsed':
case 'ok':
case 'redirected':
case 'type':
case 'url':
return response[name];
}
return target[name];
}
});
for (let key in responseProxy) {
if (typeof responseProxy[key] === 'function') {
responseProxy[key] = responseProxy[key].bind(newResponse);
}
}
return responseProxy;
}else{
return response
}
})
}
}
//添加拦截器及监听window message---调用一次
const _initAjaxProxyInstanceInterceptor=()=>{
window._ajaxProxyInstance=_ajaxProxyInstance
window._getAjaxList=(str)=>{
let list=[]
ajaxList.forEach(r=>{
if(r.url.indexOf(str)>-1||!str){
list.push(r)
}
})
return list
}
const toJson=(json)=>{return JSON.parse(JSON.stringify(json))}
let ajaxList=[]//所有ajax请求
_ajaxProxyInstance.interceptor.response.use((req,response,fetch)=>{
ajaxList.push(Object.assign({},req))
return req
})
let onRequestFlag=false;
const onRequest=()=>{
if(!onRequestFlag){
_ajaxProxyInstance.interceptor.request.use((req,response,fetch)=>{
window.postMessage({key:_ajaxProxyInstance.receiveKey,act:'onRequest',params:toJson(req)}, '*')
return req
})
onRequestFlag=true;
}
}
let onResponseFlag=false;
const onResponse=()=>{
if(!onRequestFlag){
_ajaxProxyInstance.interceptor.request.use((req,response,fetch)=>{
window.postMessage({key:_ajaxProxyInstance.receiveKey,act:'onResponse',params:toJson(req)}, '*')
return req
})
onResponseFlag=true;
}
}
window.addEventListener('message', function (e) { // 监听 message 事件
const {origin='*',data={}}=e
//监听处理ajax
const {key='',act='getList',params={}}=data;
if(key==_ajaxProxyInstance.listenerKey){
switch(act){
case 'getList':
window.postMessage({key:_ajaxProxyInstance.receiveKey,act,params:toJson(ajaxList)}, '*')
break;
case 'onRequest':
onRequest()
break;
case 'onResponse':
onResponse()
break;
default://可以进行扩展如:扩展通过filter与req来覆盖请求
break;
}
}
});
}
_initAjaxProxyInstanceInterceptor()
const _initAjaxProxyInstance=()=>{
for (const k in _ajaxProxyInstance.oriXhr) {
_ajaxProxyInstance.xhr[k] = _ajaxProxyInstance.oriXhr[k]
}
window.XMLHttpRequest = _ajaxProxyInstance.xhr;
window.fetch = _ajaxProxyInstance.fetch;
}
window.addEventListener("message", function (event) {
_initAjaxProxyInstance()
}, false);
`