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
查看完整版本: ajax劫持库ajaxHooker