scriptcat icon indicating copy to clipboard operation
scriptcat copied to clipboard

能不能增加拦截页面所有请求的API

Open Jw-23 opened this issue 5 months ago • 4 comments

我打算劫持 https://pan.xunlei.com/? 的fetch请求,设置了 @run-at: document-start ,发现竟然抢不过它。利用chrome.webRequest能否增加代理页面所有请求的API.

// ==UserScript==
// @name         迅雷网盘直接下载
// @namespace    org.jw23.xunlei
// @version      0.5.0
// @description  克服迅雷网盘的阻止下载操作
// @author       jw23
// @match        https://pan.xunlei.com/*
// @match        https://drive.pan.xunlei.com/* 
// @run-at       document-start
// ==/UserScript==

(function () {
    'use strict';

    const targetUrlKeyword = 'drive/v1/files'; // 目标API关键字

    function processResponse(url, responseText) {
        console.log(`[劫持成功] 正在处理来自 ${url} 的响应`);
        try {
            const data = JSON.parse(responseText);
            if (data && data.web_content_link) {
                console.log('成功解析到下载链接:', data.web_content_link);
                window.open(data.web_content_link, '_blank');
            } else {
                 console.log('响应中未找到 "web_content_link" 字段。');
            }
        } catch (e) {
            console.error('解析响应JSON失败:', e);
        }
    }

    // 定义应用劫持的函数
    function applyFetchHook() {
        // 在这里获取 window.fetch,此时它很可能已经是被网站修改过的版本
        const originalFetch = window.fetch;

        console.log("正在应用劫持... 当前的 fetch 函数是:", originalFetch);

        window.fetch = function(...args) {
            const [url] = args;
            const urlString = (typeof url === 'string') ? url : url.url;

            console.log(`[Fetch 劫持] 捕获到请求: ${urlString}`);

            // 调用我们保存的(可能是被网站修改过的)fetch,以保证网站功能正常
            const fetchPromise = Reflect.apply(originalFetch, this, args);

            if (urlString.includes(targetUrlKeyword)) {
                return fetchPromise.then(response => {
                    const clonedResponse = response.clone();
                    clonedResponse.text().then(text => {
                        processResponse(urlString, text);
                    });
                    return response;
                });
            }
            return fetchPromise;
        };

        console.log("Fetch 劫持已成功应用。");
    }

    // 关键:使用 setTimeout 将我们的劫持逻辑推迟到当前脚本执行队列末尾
    // 这使得我们有极大概率在网站自身的劫持脚本运行之后再运行,从而覆盖它
    setTimeout(applyFetchHook, 0);

    console.log("下载脚本已初始化,正在等待时机应用劫持...");

})();

Jw-23 avatar Jul 14 '25 14:07 Jw-23

应该与这个计划有关:https://github.com/scriptscat/scriptcat/pull/430

但是最近太忙了,先让我筹备好 v1.0.0

CodFrm avatar Jul 14 '25 15:07 CodFrm

@Jw-23

方案1加 @grant none 方案2. window.fetchunsafeWindow.fetch

@CodFrm 你要不要跟TM一样,新增脚本的预设template加@grant none ? TM作者在某次更新故意加了(,方便大家写简单脚本?)

cyfung1031 avatar Jul 14 '25 15:07 cyfung1031

@cyfung1031 可以考虑这个,很多时候,我也是直接新建脚本就开始了

你说的方案1与方案2冲突了吧,@grant none 就没有 unsafeWindow 了

CodFrm avatar Jul 14 '25 15:07 CodFrm

前面没太仔细看内容,推荐这篇文章:https://learn.scriptcat.org/%E6%B2%B9%E7%8C%B4%E6%95%99%E7%A8%8B/%E5%85%A5%E9%97%A8%E7%AF%87/Fetch%E6%8F%90%E4%BA%A4%E4%B8%8E%E8%BF%94%E5%9B%9E%E5%86%85%E5%AE%B9%E5%8A%AB%E6%8C%81/

与这个工具,应该可以帮助你更好实现功能:ajaxHooker https://scriptcat.org/zh-CN/script-show-page/637

不过还是得确认脚本@run-at document-start有没有比你需要劫持的内容更快运行

CodFrm avatar Jul 14 '25 15:07 CodFrm