前言
Fetch劫持是基于Promise进行的,我们之前已经学习过了Promise,那么现在我们来研究一下fetch劫持
2021-8-28留
以下代码可能存在错误,如果想直接摘抄请使用这个代码
2021-8-28下午留
我又参考了一部分代码和资料,提出一个相对来说目前可能正确的fetch代理
之前代码出现报错是因为this指向问题,为了防止调用函数出错,我们传入了原response的this指针,然后有些网页喜欢往上挂载函数以及乱读乱写
所以获取了this指针后就饶过了我们的proxy代理,并且还在使用proxy代理以及非proxy指针,导致冲突问题。
这里我们使用了proxy直接传入原reponse以及代理原reponse对象
保证写入的数据都在reponse上,以及网页获取的this也在reponse上
这时候调用函数会经过我们的proxy上,可以比之前的可靠性更好一点
如果使用该代码出现错误请立刻停止继续使用,并反馈。
更推荐使用cxxjackie的进行fetch劫持!!!
let oldfetch=fetch
function newobj(){}
function fuckfetch(...bianliang){
return new Promise(function(resolve, reject){
oldfetch(...bianliang).then(function(response) {
let handler = {
get: function(target, prop, receiver) {
console.log('get',target, prop, receiver)
if(typeof Reflect.get(target,prop)==='function')
{
if(Reflect.get(target,prop+'proxy')===undefined)
{
target[prop+'proxy']=new Proxy(Reflect.get(target,prop), {
apply: (target, thisArg, argumentsList)=> {
console.log('fetchfunction',target.name, response, argumentsList)
return Reflect.apply(target, response, argumentsList);
}
});
}
return Reflect.get(target,prop+'proxy')
}
return Reflect.get(target, prop);
},
set(target, prop, value) {
return Reflect.set(target, prop, value);
},
};
let proxy=new Proxy(response, handler)
resolve(proxy)
})
});
}
window.fetch=fuckfetch
开始
一个基本的fetch还是很简单的
fetch('http://example.com/movies.json')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
fetch提交一个地址,然后返回了一个promise,对promise挂载hen,收到了一个response,然后返回response的json函数返回的内容
我们可以看到现在a是履行的
返回的是一个Response对象,并且json在原型链上
为了保守性和通用性,我们应该对promise返回的response对象进行劫持
这里我们开始对fetch函数进行劫持吧!
实战
let oldfetch=fetch
function fuckfetch(arguments){
return new Promise(function(resolve, reject){
});
}
由于fetch返回了一个promise,所以我们也需要返回一个promise,oldfetch是为了保存原fetch的引用,因为我们会替换掉window上fetch函数,对fetch实现一个劫持的功能。arguments是为了收集传入函数的参数,并且原封不动的传入到原fetch中。
let oldfetch=fetch
function fuckfetch(arguments){
return new Promise(function(resolve, reject){
oldfetch(arguments)
});
}
由于我们是劫持fetch函数嘛,我们需要在promise进行fetch的函数调用,并传入调用我们函数的参数原封不动的传给他,只要我们不resolve/reject,这个函数永远都是pengding的状态,所以我们可以放心干,大胆干!
let oldfetch=fetch
function fuckfetch(arguments){
return new Promise(function(resolve, reject){
oldfetch(arguments).then(function(response) {
console.log(response)
resolve('niub')
})
});
}
这里对原fetch返回的promise挂载了一个then,收到response并输出出来,然后将我们这个函数的返回的promise设置为履行,值为国粹niub。
我们首先测试一下
可以看到输出的url并不是我们提交的,也报错了一个404
我们调试一下看看,因为我们的函数没有实际功能,所以100%是在oldfetch上出错了,打断点看一点
这里看到arguments是new promise传给我们的参数,我们疏忽了!
我们应该获取到fuckfetch上的参数,应该怎么办呢?
可以考虑用变量拓展运算符
let oldfetch=fetch
function fuckfetch(...bianliang){
return new Promise(function(resolve, reject){
oldfetch(...bianliang).then(function(response) {
console.log(response)
resolve('Fuccck')
})
});
}
window.fetch=fuckfetch
...会收集没有赋值到参数上变量的所有其他剩余参数,而在函数体内对变量使用...,则会将其还原至原来的参数样子。
因为我们这里没有其他参数,所以...bianliang会收集所有传给这个函数的参数。
可以看到...c收集了所有剩余参数。
而在函数体内使用...c,会将收集的剩余参数形成的数组重新还原成参数的形式
修改之后可以看到非常成功,然后我们可以开始对Response对象进行Proxy劫持了!
let oldfetch=fetch
function fuckfetch(...bianliang){
return new Promise(function(resolve, reject){
oldfetch(...bianliang).then(function(response) {
let handler = {
get: function(target, prop, receiver) {
console.log('target',target, prop, receiver)
return Reflect.get(target, prop);
},
set(target, prop, value) {
console.log('set',target, prop, value)
return Reflect.set(target, prop, value);
},
};
let proxy=new Proxy(response, handler)
resolve(proxy)
})
});
}
window.fetch=fuckfetch
由于对对象常见的操作我认为只有set和get,所以这里目前仅对这两个操作进行劫持,如果存在其他的,我们可以查询手册,继续添加。
对其进行调用测试,发现报出错误
a.then(function(response) {console.log('getresponse',response)
return response.json();
})
我们使用的是response.json()
会触发get属性,获取到json的函数并且调用,但是由于我们进行了target包装
所以调用的变成了Proxy对象的json函数,由于根本没有,所以会触发报错。
这里会不会想到xhr劫持部分?我们可以模仿xhr劫持部分对函数的指向进行劫持。
let oldfetch=fetch
function newobj(){}
function fuckfetch(...bianliang){
return new Promise(function(resolve, reject){
oldfetch(...bianliang).then(function(response) {
let tagetobk=new newobj();
tagetobk.oldfetch=response;
let handler = {
get: function(target, prop, receiver) {
console.log('get',target, prop, receiver)
if(prop==='oldfetch'){
return Reflect.get(target,prop);
}
if(typeof Reflect.get(target.oldfetch,prop)==='function')
{
if(Reflect.get(target.oldfetch,prop+'proxy')===undefined)
{
target.oldfetch[prop+'proxy']=new Proxy(Reflect.get(target.oldfetch,prop), {
apply: function(target, thisArg, argumentsList) {
return Reflect.apply(target, thisArg.oldfetch, argumentsList);
}
});
}
return Reflect.get(target.oldfetch,prop+'proxy')
}
return Reflect.get(target.oldfetch, prop);
},
set(target, prop, value) {
console.log('set',target, prop, value)
return Reflect.set(target.oldfetch, prop, value);
},
};
let proxy=new Proxy(tagetobk, handler)
resolve(proxy)
})
});
}
window.fetch=fuckfetch
我们可以在函数的proxy内进行判断
target.oldfetch[prop+'proxy']=new Proxy(Reflect.get(target.oldfetch,prop), {
apply: function(target, thisArg, argumentsList) {
console.log('function',target, thisArg, argumentsList)
if(target.name==='json'){
return {a:6,b:6,c:6}
}
return Reflect.apply(target, thisArg.oldfetch, argumentsList);
}
});
这里我输出了function+target,thisArg,argumentsList三个参数
第一个target是我们调用的目标函数,我们可以对这个函数调用.name来获得他的函数名字符,然后与json对比,如果相等了
就返回一些我们特定的内容,如果不相等,则调用原来的函数并返回内容。
这里可以看到返回了我们设定的内容,这个对象下的其他函数也可以通过这种办法进行劫持,这里只是以json函数进行举例
警告
proxy会拖慢网页的执行效率,在频繁数据交互的情况下不推荐使用,以及希望大家时候的时候可以考虑在fuckfetch函数内对参数进行判断,有针对性的对fetch进行劫持过滤,proxy虽好,可不要贪杯哦~
结语
撒花~