为什么这段代码不起作用?我正在创建一个 Firefox 扩展,但代码不是 运行。但是,如果我将代码粘贴到控制台中,它就可以工作

Why is this code not working? I am creating a Firefox extension but the code is not running. But if I paste the code into the console it works

我制作了一个 firefox 扩展程序来获取所有请求 url 并显示它们。但是代码只有在我将它粘贴到控制台时才有效。

当扩展加载时它没有显示任何错误,似乎它不会 运行

这里是完整的代码

xhrScript.js

(function(){

    const proxiedOpen = XMLHttpRequest.prototype.open;
    window.XMLHttpRequest.prototype.open = function ( _, url) {
        this.__URL = url;
        return proxiedOpen.apply(this, arguments);
    };

    const proxiedSend = window.XMLHttpRequest.prototype.send;
    window.XMLHttpRequest.prototype.send = function () {
        const { protocol, host } = window.location;
        // showing only when it paste in console
        console.log("full request url ", `${protocol}//${host}${this.__URL}`);
        return proxiedSend.apply(this, [].slice.call(arguments));
    };

})();

// this works all times
document.body.style.border = "7px solid blue";

manifest.json

{
    "manifest_version": 2,
    "name": "XHR request urls",
    "version": "1.0",
    "description": "get all the request url's",

    "content_scripts": [
      {
        "matches": ["*://*/*"],
        "js": ["xhrScript.js"]
      }
    ]  
}

如您所见,最后一行是 document.body.style.border = "7px solid blue";,每次都可以正常工作。但是 XMLHttpRequest opensend 方法不起作用。仅当我将代码粘贴到控制台时才有效。

如果您想查看示例,可以尝试在 devTools 控制台中复制并粘贴 https://reactjs.org 中的 xhrScript.js 代码(这是一个 SPA,因此很容易检查我想要什么),并查看所有请求。

我不知道为什么这段代码粘贴到控制台时只有运行秒

内容脚本 运行 在隔离的 JavaScript 环境中,这意味着 window 及其内容与页面隔离,因此当您修改它时,您只修改内容脚本的版本。

有两种解决方案:

  1. Firefox 专用。

    使用wrappedJSObjectexportFunction访问页面上下文(more info):

    const urls = new WeakMap();
    const origXhr = hookPagePrototype('XMLHttpRequest', {
      open(method, url) {
        urls.set(this, url);
        return origXhr.open.apply(this, arguments);
      },
      send() {
        console.log('Sending', new URL(urls.get(this), location).href);
        return origXhr.send.apply(this, arguments);
      },
    });
    
    function hookPagePrototype(protoName, funcs) {
      const proto = wrappedJSObject[protoName].prototype;
      const oldFuncs = {};
      for (const [name, fn] of Object.entries(funcs)) {
        oldFuncs[name] = exportFunction(proto[name], wrappedJSObject);
        proto[name] = exportFunction(fn, wrappedJSObject);
      }
      return oldFuncs;
    }
    
  2. Chrome兼容。

    使用 DOM 脚本来 运行 页面上下文中的代码:instruction.

    它不会在受严格内容安全策略 (CSP) 保护的页面上运行,该策略会阻止脚本执行,因此在为 Firefox 编写扩展程序时,我们应该改用 wrappedJSObject 方法。