cxxjackie
发表于 2022-11-19 20:49:59
小黑. 发表于 2022-11-19 16:10
新版hook怎么使用
新版只改了data和headers的读取方式,由回调函数改为直接读取,其他和原来一样。
涛之雨
发表于 2022-12-3 23:15:43
写的不错,以后不要再写了,私我让我发
!(data/attachment/forum/202212/03/231358fe51ki5zgvyf3exk.jpg)
!(data/attachment/forum/202212/03/231334r2qs20eq077e2777.gif)
Major
发表于 2023-1-1 11:18:21
目的:想实现劫持一个json请求(请求A)。然后将拿到的请求(请求A)判断后,再发json请求B,将请求B的结果,修改到请求A,再将A返回。下方的代码无法实现这个运行。因为请求B的内容放到A的劫持函数中会变成一个promise对象。promise对象的then中无法赋值到外层。
// ==UserScript==
// @name 【Major】劫持并修改
// @namespace https://bbs.tampermonkey.net.cn/
// @version 0.1.2
// @descriptiontry to take over the world!
// @author You
// @match http*://*/lists?cid=*
// @match http*://*/show?id=*
// @require https://scriptcat.org/lib/637/1.0.0/ajaxHooker.js
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @run-at document-start
// ==/UserScript==
// 在此处键入代码……
unsafeWindow.GM_cookie = GM_cookie;
unsafeWindow.GM_xmlhttpRequest = GM_xmlhttpRequest;
let configf = {
hookJson: function(){
console.log('hook:','start')
ajaxHooker.hook(request => {
console.log('request.url:',request.url)
console.log(request.data)
console.log('request.method:',request.method)
if (request.url === '/api/show' && request.method === 'POST') {
console.log('hoolk:','sess')
// request.data = val => {
// const postData = JSON.parse(val);
// console.log(postData);
// return JSON.stringify(postData);
// };
request.response = res => {
try{
oldJson = JSON.parse(res.responseText);
if(oldJson.is_see=== false){
// 这里返回的是一个 promise对象,怎样才能把值取出来,并修改到劫持中再返回???
let mes = configf.awaitMessage();
mes.then((getmes) => {
console.log("result", getmes);
oldJson.QQ = getmes.qq;
oldJson.phone = getmes.phone;
oldJson.wechat= getmes.wechat;
oldJson.address = getmes.address;
oldJson.is_see= true;
console.log("result>>>>>", oldJson);
res.responseText = JSON.stringify(oldJson);
})
};
}catch (e){
console.log('erro:',e)
res.responseText
};
};
};
});
},
getmessage:function(){
return new Promise(function (resolve, reject) {
let url = "http://127.0.0.1:16999/ylyf/api/post"
let id = configf.getUrlParams();
console.log(id)
id = id.id;
GM_xmlhttpRequest({
method: "POST",
url: url,
data:JSON.stringify({"id":id}),
onload: function(res){
if(res.status === 200){
console.log(res.responseText)
}else{
console.log('send 数据失败'+'返回代码:'+String(res.status))
};
resolve(res.responseText)
},
onerror : function(err){
console.log('send 数据遇到错误',err)
reject();
}
});
});
},
awaitMessage:async function(){
res = await configf.getmessage();
localStorage.message = res;
return res
},
};
(function(){
configf.hookJson();
})()
cxxjackie
发表于 2023-1-1 12:07:19
Major 发表于 2023-1-1 11:18
目的:想实现劫持一个json请求(请求A)。然后将拿到的请求(请求A)判断后,再发json请求B,将请求B的结果 ...
确实不行,这属于异步的劫持,response的回调函数只能接受同步的结果,解决方法也有,看我6楼和10楼的回复。后面看看这个需求如果常见的话,我考虑整合到这个库里,就是实现起来挺麻烦的,不一定适用所有情况。
Major
发表于 2023-1-1 12:32:15
cxxjackie 发表于 2023-1-1 12:07
确实不行,这属于异步的劫持,response的回调函数只能接受同步的结果,解决方法也有,看我6楼和10楼的回 ...
这个需求常见啊,是劫持的灵魂,期待期待!!!!
Major
发表于 2023-1-1 13:29:57
cxxjackie 发表于 2023-1-1 12:07
确实不行,这属于异步的劫持,response的回调函数只能接受同步的结果,解决方法也有,看我6楼和10楼的回 ...
我用 localStorage(请求B的数据存这里) 临时做了一个中转貌似 可以运行。但是不是很流畅,经常遇到,请求B中的数据变更了,但是 A 上的数据没变更。但是多刷新几次又正常了,有没有可能找一个中间件改进一下的,这样是不是简单一点
cxxjackie
发表于 2023-1-1 22:45:33
Major 发表于 2023-1-1 13:29
我用 localStorage(请求B的数据存这里) 临时做了一个中转貌似 可以运行。但是不是很流畅,经常遇到,请 ...
不行的,这个只是因为请求的快慢不一,AB的完成时间应该差不多,多次刷新导致B比A先完成了,所以B能改变A的结果,但如果A先完成就无效了。
这个加进库里主要的难点在于:无法确定监听请求完成的事件是readystatechange、load还是loadend,或者其他什么野路子,而且监听事件有两种方式,addEventListener和onXXX。这个要劫持的话不是不能做到,而是考虑所有情况,代码量会很大,再加上很多网站也喜欢劫持xhr,一些冲突的情况会比较棘手。如果自己写的话,你可以根据特定请求的代码有针对性的劫持,但是写成库就得把所有事件都覆盖到,对于用不到这个特性的脚本来说,这部分多余的代码很累赘,所以是要有所取舍的。
Major
发表于 2023-1-1 23:54:16
cxxjackie 发表于 2023-1-1 22:45
不行的,这个只是因为请求的快慢不一,AB的完成时间应该差不多,多次刷新导致B比A先完成了,所以B能改变A ...
能针对这个需求单独写一个库吗,感觉很需要。劫持onload那个有点太高深了,搞不太懂,你直接封装的库 好用多了!!!!
Major
发表于 2023-1-1 23:56:34
脚本体验师001 发表于 2022-9-26 23:07
哈哈看到setTimeout就八九不离那个谱了,我研究研究
兄弟,你研究好了吗,能否共享你的完整代码我套用一下
cxxjackie
发表于 2023-1-2 12:23:04
Major 发表于 2023-1-1 23:54
能针对这个需求单独写一个库吗,感觉很需要。劫持onload那个有点太高深了,搞不太懂,你直接封装的库 好 ...
你先试试这段代码能不能行吧,回头我再考虑库怎么搞:
const setOnload = Object.getOwnPropertyDescriptor(XMLHttpRequestEventTarget.prototype, 'onload').set;
const getResponseText = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, 'responseText').get;
const xhrOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(...args1) {
const xhr = this;
if (args1 === '/api/show') {
let onload;
Object.defineProperty(xhr, 'onload', {
configurable: true,
enumerable: true,
get: () => onload,
set: fn => {
onload = fn;
const fakeOnload = function(...args2) {
configf.awaitMessage().then(getmes => {
Object.defineProperty(xhr, 'responseText', {
configurable: true,
enumerable: true,
get: () => {
const oldJson = JSON.parse(getResponseText.call(xhr));
if (oldJson.is_see === false) {
oldJson.QQ = getmes.qq;
oldJson.phone = getmes.phone;
oldJson.wechat = getmes.wechat;
oldJson.address = getmes.address;
oldJson.is_see = true;
}
return JSON.stringify(oldJson);
}
});
fn.apply(xhr, args2);
}, () => fn.apply(xhr, args2));
};
setOnload.call(xhr, fakeOnload);
}
});
}
return xhrOpen.apply(xhr, args1);
};
页:
1
2
3
[4]
5
6
7
8
9
10
11
12
13