上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
返回列表 发新帖
楼主: cxxjackie - 

ajax劫持库ajaxHooker

  [复制链接]
  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    22

    主题

    862

    回帖

    1361

    积分

    荣誉开发者

    积分
    1361

    荣誉开发者卓越贡献油中2周年生态建设者油中3周年挑战者 lv2

    发表于 2022-11-19 20:49:59 | 显示全部楼层
    小黑. 发表于 2022-11-19 16:10
    新版hook怎么使用

    新版只改了data和headers的读取方式,由回调函数改为直接读取,其他和原来一样。
    回复
    订阅

    使用道具 举报

  • TA的每日心情
    慵懒
    2023-11-28 11:18
  • 签到天数: 9 天

    [LV.3]偶尔看看II

    16

    主题

    153

    回帖

    313

    积分

    荣誉开发者

    积分
    313

    荣誉开发者油中2周年生态建设者油中3周年挑战者 lv2

    发表于 2022-12-3 23:15:43 | 显示全部楼层

    写的不错,以后不要再写了,私我让我发

    jpg

    gif

    回复

    使用道具 举报

    该用户从未签到

    16

    主题

    56

    回帖

    90

    积分

    初级工程师

    积分
    90

    新人报道

    发表于 2023-1-1 11:18:21 | 显示全部楼层
    目的:想实现劫持一个json请求(请求A)。然后将拿到的请求(请求A)判断后,再发json请求B,将请求B的结果,修改到请求A,再将A返回。下方的代码无法实现这个运行。因为请求B的内容放到A的劫持函数中会变成一个promise对象。promise对象的then中无法赋值到外层。
    1. // ==UserScript==
    2. // [url=home.php?mod=space&uid=23356]@name[/url]         【Major】劫持并修改
    3. // @namespace    https://bbs.tampermonkey.net.cn/
    4. // @version      0.1.2
    5. // @description  try to take over the world!
    6. // @author       You
    7. // [url=home.php?mod=space&uid=52134]@match[/url]        http*://*/lists?cid=*
    8. // @match        http*://*/show?id=*
    9. // @require      https://scriptcat.org/lib/637/1.0.0/ajaxHooker.js
    10. // @grant        GM_xmlhttpRequest
    11. // @grant        unsafeWindow
    12. // @run-at       document-start
    13. // ==/UserScript==

    14. // 在此处键入代码……
    15. unsafeWindow.GM_cookie = GM_cookie;
    16. unsafeWindow.GM_xmlhttpRequest = GM_xmlhttpRequest;

    17. let configf = {
    18.     hookJson: function(){
    19.         console.log('hook:','start')
    20.         ajaxHooker.hook(request => {
    21.             console.log('request.url:',request.url)
    22.             console.log(request.data)
    23.             console.log('request.method:',request.method)
    24.             if (request.url === '/api/show' && request.method === 'POST') {
    25.                 console.log('hoolk:','sess')

    26.                 // request.data = val => {
    27.                 //     const postData = JSON.parse(val);
    28.                 //     console.log(postData);
    29.                 //     return JSON.stringify(postData);
    30.                 // };

    31.                 request.response = res => {
    32.                     try{
    33.                         oldJson = JSON.parse(res.responseText);
    34.                         if(oldJson.is_see  === false){
    35.                             // 这里返回的是一个 promise对象,怎样才能把值取出来,并修改到劫持中再返回???
    36.                             let mes = configf.awaitMessage();
    37.                             mes.then((getmes) => {
    38.                                 console.log("result", getmes);
    39.                                 oldJson.QQ = getmes.qq;
    40.                                 oldJson.phone   = getmes.phone;
    41.                                 oldJson.wechat  = getmes.wechat;
    42.                                 oldJson.address = getmes.address;
    43.                                 oldJson.is_see  = true;
    44.                                 console.log("result>>>>>", oldJson);
    45.                                 res.responseText = JSON.stringify(oldJson);
    46.                             })

    47.                         };                        
    48.                     }catch (e){
    49.                         console.log('erro:',e)
    50.                         res.responseText
    51.                     };

    52.                 };
    53.             };
    54.         });
    55.     },

    56.     getmessage:function(){
    57.         return new Promise(function (resolve, reject) {
    58.             let url = "http://127.0.0.1:16999/ylyf/api/post"
    59.             let id = configf.getUrlParams();
    60.             console.log(id)
    61.             id = id.id;
    62.             GM_xmlhttpRequest({
    63.                 method: "POST",
    64.                 url: url,
    65.                 data:JSON.stringify({"id":id}),
    66.                 onload: function(res){
    67.                     if(res.status === 200){
    68.                         console.log(res.responseText)
    69.                     }else{
    70.                         console.log('send 数据失败'+'返回代码:'+String(res.status))
    71.                     };
    72.                     resolve(res.responseText)
    73.                 },
    74.                 onerror : function(err){
    75.                     console.log('send 数据遇到错误',err)
    76.                     reject();
    77.                 }
    78.             });
    79.         });

    80.     },



    81.     awaitMessage:async function(){
    82.         res = await configf.getmessage();
    83.         localStorage.message = res;
    84.         return res
    85.     },


    86. };


    87. (function(){


    88.     configf.hookJson();


    89. })()
    复制代码
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    22

    主题

    862

    回帖

    1361

    积分

    荣誉开发者

    积分
    1361

    荣誉开发者卓越贡献油中2周年生态建设者油中3周年挑战者 lv2

    发表于 2023-1-1 12:07:19 | 显示全部楼层
    Major 发表于 2023-1-1 11:18
    目的:想实现劫持一个json请求(请求A)。然后将拿到的请求(请求A)判断后,再发json请求B,将请求B的结果 ...

    确实不行,这属于异步的劫持,response的回调函数只能接受同步的结果,解决方法也有,看我6楼和10楼的回复。后面看看这个需求如果常见的话,我考虑整合到这个库里,就是实现起来挺麻烦的,不一定适用所有情况。
    回复

    使用道具 举报

    该用户从未签到

    16

    主题

    56

    回帖

    90

    积分

    初级工程师

    积分
    90

    新人报道

    发表于 2023-1-1 12:32:15 | 显示全部楼层
    cxxjackie 发表于 2023-1-1 12:07
    确实不行,这属于异步的劫持,response的回调函数只能接受同步的结果,解决方法也有,看我6楼和10楼的回 ...

    这个需求常见啊,是劫持的灵魂,期待期待!!!!
    回复

    使用道具 举报

    该用户从未签到

    16

    主题

    56

    回帖

    90

    积分

    初级工程师

    积分
    90

    新人报道

    发表于 2023-1-1 13:29:57 | 显示全部楼层
    cxxjackie 发表于 2023-1-1 12:07
    确实不行,这属于异步的劫持,response的回调函数只能接受同步的结果,解决方法也有,看我6楼和10楼的回 ...

    我用 localStorage(请求B的数据存这里) 临时做了一个中转貌似 可以运行。但是不是很流畅,经常遇到,请求B中的数据变更了,但是 A 上的数据没变更。但是多刷新几次又正常了,有没有可能找一个中间件改进一下的,这样是不是简单一点
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    22

    主题

    862

    回帖

    1361

    积分

    荣誉开发者

    积分
    1361

    荣誉开发者卓越贡献油中2周年生态建设者油中3周年挑战者 lv2

    发表于 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,一些冲突的情况会比较棘手。如果自己写的话,你可以根据特定请求的代码有针对性的劫持,但是写成库就得把所有事件都覆盖到,对于用不到这个特性的脚本来说,这部分多余的代码很累赘,所以是要有所取舍的。
    回复

    使用道具 举报

    该用户从未签到

    16

    主题

    56

    回帖

    90

    积分

    初级工程师

    积分
    90

    新人报道

    发表于 2023-1-1 23:54:16 | 显示全部楼层
    cxxjackie 发表于 2023-1-1 22:45
    不行的,这个只是因为请求的快慢不一,AB的完成时间应该差不多,多次刷新导致B比A先完成了,所以B能改变A ...

    能针对这个需求单独写一个库吗,感觉很需要。劫持onload那个有点太高深了,搞不太懂,你直接封装的库 好用多了!!!!
    回复

    使用道具 举报

    该用户从未签到

    16

    主题

    56

    回帖

    90

    积分

    初级工程师

    积分
    90

    新人报道

    发表于 2023-1-1 23:56:34 | 显示全部楼层
    脚本体验师001 发表于 2022-9-26 23:07
    哈哈看到setTimeout就八九不离那个谱了,我研究研究

    兄弟,你研究好了吗,能否共享你的完整代码我套用一下
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    22

    主题

    862

    回帖

    1361

    积分

    荣誉开发者

    积分
    1361

    荣誉开发者卓越贡献油中2周年生态建设者油中3周年挑战者 lv2

    发表于 2023-1-2 12:23:04 | 显示全部楼层
    Major 发表于 2023-1-1 23:54
    能针对这个需求单独写一个库吗,感觉很需要。劫持onload那个有点太高深了,搞不太懂,你直接封装的库 好 ...

    你先试试这段代码能不能行吧,回头我再考虑库怎么搞:
    1. const setOnload = Object.getOwnPropertyDescriptor(XMLHttpRequestEventTarget.prototype, 'onload').set;
    2. const getResponseText = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, 'responseText').get;
    3. const xhrOpen = XMLHttpRequest.prototype.open;
    4. XMLHttpRequest.prototype.open = function(...args1) {
    5.     const xhr = this;
    6.     if (args1[1] === '/api/show') {
    7.         let onload;
    8.         Object.defineProperty(xhr, 'onload', {
    9.             configurable: true,
    10.             enumerable: true,
    11.             get: () => onload,
    12.             set: fn => {
    13.                 onload = fn;
    14.                 const fakeOnload = function(...args2) {
    15.                     configf.awaitMessage().then(getmes => {
    16.                         Object.defineProperty(xhr, 'responseText', {
    17.                             configurable: true,
    18.                             enumerable: true,
    19.                             get: () => {
    20.                                 const oldJson = JSON.parse(getResponseText.call(xhr));
    21.                                 if (oldJson.is_see === false) {
    22.                                     oldJson.QQ = getmes.qq;
    23.                                     oldJson.phone = getmes.phone;
    24.                                     oldJson.wechat = getmes.wechat;
    25.                                     oldJson.address = getmes.address;
    26.                                     oldJson.is_see = true;
    27.                                 }
    28.                                 return JSON.stringify(oldJson);
    29.                             }
    30.                         });
    31.                         fn.apply(xhr, args2);
    32.                     }, () => fn.apply(xhr, args2));
    33.                 };
    34.                 setOnload.call(xhr, fakeOnload);
    35.             }
    36.         });
    37.     }
    38.     return xhrOpen.apply(xhr, args1);
    39. };
    复制代码
    回复

    使用道具 举报

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表