Skip to content

[BUG] 脚本猫新版的 GM_xmlhttpRequest 问题 #1080

@TFSN20

Description

@TFSN20

问题描述

如下封装了GM_xmlhttpRequest

    const tools = {
        sleep: t => new Promise(res => setTimeout(res, t)),// 箭头函数体只有一句,可以省略return
        net: {
            change: (str, withCookie, autoFollow302) => {
                str = str.trim(); //去除文本首位\s
                let method = str.match(/(.*?)\s/)[1];
                let url = str.match(/\s(.*?)\s/)[1];
                str = str.replace(/.*?\n/, ''); //去除第一行
                let data = /\n\s*\n\s*(.*)$/m.test(str) ? str.slice(str.match(/\n\s*\n\s*(.*)$/m).index).trim() : ''; //获取请求体,没有则返回'', 用slice截取防止请求体含有\n时出错
                str = str.replace(new RegExp(data), '').trim(); //去除data
                str = str.replace(/^(\s*?)(\S.*)/gm, `$2`); //去除每行行首的\s
                str = str.replace(/\sContent-Length:.*/im, ''); //去除Content-Length所在行,不用/^\sContent-Length:./im, 这样做会多一个空白行避免一些问题
                str = str.replace(/\sHOST.*/im, ''); //去除host可以避免请求为302时后续自动跟随的问题
                str = withCookie ? str : str.replace(/\s*cookie:.*/im, '')	//去除cookie所在行,不用/^\s*cookie.*/im, 这样做会多一个空白行
                str = str.replace(/\sHOST.*/im, '');

                if (!autoFollow302) {
                    str = str.replace(/\sReferer.*/im, '');
                    str = str.replace(/\sOrigin.*/im, '');
                    str = str.replace(/\scache-control.*/im, '');

                }
                let headers = {}, h = str.match(/(\S*?):\s*(\S.*)/mg);
                // GM_log(h)

                h.forEach(e => {
                    let t = e.match(/(\S*?):\s*(.*)/);
                    headers[t[1]] = t[2].replace(/\s*$/, '');//去除行尾\s,避免一下总没错吧
                });

                //去除浏览器默认携带的请求头
                // if (!/dnt/i.test(str)) headers.dnt = '';
                // //if (!/accept/i.test(str)) headers.accept='';
                // if (!/user-agent/i.test(str)) headers['user-agent'] = '';
                // if (!/sec-ch-ua/i.test(str)) headers['sec-ch-ua'] = '';
                // if (!/sec-ch-ua-mobile/i.test(str)) headers['sec-ch-ua-mobile'] = '';
                // if (!/sec-ch-ua-platform/i.test(str)) headers['sec-ch-ua-platform'] = '';
                // if (!/sec-fetch-dest/i.test(str)) headers['sec-fetch-dest'] = '';
                // if (!/sec-fetch-mode/i.test(str)) headers['sec-fetch-mode'] = '';
                // if (!/sec-fetch-site/i.test(str)) headers['sec-fetch-site'] = '';
                // //if (!/accept-language/i.test(str)) headers['accept-language']='';
                // if (!/accept-encoding/i.test(str)) headers['accept-encoding'] = '';

                return { url, method, data, headers }
            },
        },
        waitForSpecificTime: async (expectedTime, timestamp) => {
            if (timestamp == undefined) {
                timestamp = await tools.net.send(`
                GET https://time.is/t/?zh.0.347.2464.0p.480.43d.1574683214663.1594044507830. HTTP/1.1
                `, onload = (xhr => {
                    let timestamp = xhr.response.substring(0, 13);
                    console.log(`timestamp: ${timestamp}`);
                    return timestamp
                }), anonymous = true, withCookie = true);
            }


            // 定义一个将 HH:mm:ss 格式的时间字符串转换为今日的 Date 对象的函数
            const parseTimeToTodayDate = (timeString) => {
                const now = new Date();
                const [hours, minutes, seconds] = timeString.split(':').map(Number);
                return (new Date(now.getFullYear(), now.getMonth(), now.getDate(), hours, minutes, seconds)).getTime()
            };

            // 计算预期执行时间与当前时间的差异(毫秒)
            const currentTime = timestamp;
            const expectedDateTime = parseTimeToTodayDate(expectedTime);
            const millisecondsToWait = expectedDateTime - currentTime;
            (typeof GM_log === "function" ? GM_log : console.log)('脚本启动......');
            // 如果当前时间小于预期时间,则等待差异时间
            if (millisecondsToWait > 0) {
                (typeof GM_log === "function" ? GM_log : console.log)(`等待 ${millisecondsToWait / 1000} 秒后执行脚本......`);
                await new Promise(resolve => setTimeout(resolve, millisecondsToWait));
            } else {
                (typeof GM_log === "function" ? GM_log : console.log)('立即执行脚本');
            }
        },
    };
    tools.net.send = (str, onload = (xhr => xhr), anonymous = false, withCookie = false, autoFollow302 = true) => {
        let t = tools.net.change(str, withCookie, autoFollow302);
        return new Promise((resolve, reject) => {
            t.anonymous = anonymous;
            t.onload = (xhr) => {
                resolve(onload(xhr))
            };
            t.onerror = _ => { console.log(_);GM_log('some errors:' + _) };
            t.onreadystatechange = _ => {
                if (_.status == 0) resolve('联系服务器之前发生了错误')
            }
            GM_xmlhttpRequest(t)
        })
    };

执行await tools.waitForSpecificTime('7:04:20')t.onerror = _ => { console.log(_);GM_log('some errors:' + _) }打印出来错误

{
    "DONE": 4,
    "HEADERS_RECEIVED": 2,
    "LOADING": 3,
    "OPENED": 1,
    "UNSENT": 0,
    "RESPONSE_TYPE_TEXT": "text",
    "RESPONSE_TYPE_ARRAYBUFFER": "arraybuffer",
    "RESPONSE_TYPE_BLOB": "blob",
    "RESPONSE_TYPE_DOCUMENT": "document",
    "RESPONSE_TYPE_JSON": "json",
    "RESPONSE_TYPE_STREAM": "stream",
    "error": "Failed to execute 'fetch' on 'WorkerGlobalScope': Request with GET/HEAD method cannot have body.",
    "readyState": 4,
    "response": null,
    "responseHeaders": "",
    "responseText": "",
    "status": 0,
    "statusText": ""
}

这个应该请求体为""导致的,修复:

tools.net.send = (str, onload = (xhr => xhr), anonymous = false, withCookie = false, autoFollow302 = true) => {
  let t = tools.net.change(str, withCookie, autoFollow302);

  // ✅ 关键:GET/HEAD 不要传 data(哪怕是 '')
  if (/^(GET|HEAD)$/i.test(t.method) && (t.data === '' || t.data == null)) {
    delete t.data;
  }

  return new Promise((resolve, reject) => {
    t.anonymous = anonymous;
    t.onload = (xhr) => resolve(onload(xhr));
    t.onerror = _ => { console.log(_); (typeof GM_log === "function" ? GM_log : console.log)('some errors:' + JSON.stringify(_, null, 2)); };
    t.onreadystatechange = _ => {
      if (_.status == 0) resolve('联系服务器之前发生了错误')
    }
    GM_xmlhttpRequest(t);
  });
};

另外

t.onreadystatechange = _ => {
    if (_.status == 0) resolve('联系服务器之前发生了错误')
}

新版本应该发生了变化,导致直接resolve('联系服务器之前发生了错误'),注释掉就好了,但是就没办法判断是否是不是在外网里导致的。

重现步骤

...

脚本猫版本

v1.2.1

操作系统以及浏览器信息

edge最新版

补充信息 (选填)

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions