从 Greasemonkey 脚本拦截 XMLHttpRequest 失败

Intercept XMLHttpRequest from Greasemonkey script fails

我试图操纵一个网站使用 Greasemonkey(安装了 4.9 版)完成的 XMLHttpRequest。拦截应该很简单()但对我不起作用。也许更新版本的 Greasemonkey 改变了一些事情?

我显然尝试了链接问题中的示例,但它们没有任何效果 - 尽管我在自定义打开函数中有一个 console.log(...),但控制台中没有打印任何内容。

接下来,我尝试了 unsafeWindow。它不应该被需要。我的带有 @grant none 和文档 (see here) 的用户脚本 运行 说我的脚本应该 运行 在内容范围内。

使用 unsafeWindow 我得到了效果,但它完全破坏了 XMLHttpRequest

// ==UserScript==
// @name          Test
// @version       1
// @include       *
// @run-at        document-start
// @grant         none
// ==/UserScript==

"use strict";

let realOpen = unsafeWindow.XMLHttpRequest.prototype.open

console.log("Real: " + realOpen)

unsafeWindow.XMLHttpRequest.prototype.open = function() {
  console.log("Called for " + this + " with URL: " + arguments[0])

  //call original
  return realOpen.apply(this, arguments)
};

window.addEventListener ("load", function() {
  console.log ("Page loaded");
});

console.log("Unsafe: ", unsafeWindow.XMLHttpRequest.prototype.open.toString())
console.log("Normal: ", XMLHttpRequest.prototype.open.toString())

这会在控制台中产生以下输出:

Real: function open() {
    [native code]
}

Unsafe:  function() {
    console.log("Called for " + this + " with URL: " + arguments[0])

    //call original
    return realOpen.apply(this, arguments)
  }

Normal:  function open(method, url) {
    // only include method and url parameters so the function length is set properly
    if (arguments.length >= 2) {
      let newUrl = new URL(arguments[1], document.location.href);
      arguments[1] = newUrl.toString();
    }
    return origOpen.apply(this, arguments);
  }

==> Page loaded

如前所述,XMLHttpRequest 的功能已损坏。当我使用 Firefox 开发人员控制台进一步查看时,我得到了这个

>> window.XMLHttpRequest.prototype.open
Restricted {  }

window 上设置的任何属性(如 window.foobar = "foobar")在控制台中不存在,但在 unsafeWindow 上设置的属性存在。我认为这与 Greasemonkey 的沙盒有关。

为什么我使用 @grant none 时还有两个版本的 XMLHttpRequest?为什么我的自定义功能被限制了?我可以避免吗?为什么我在 window 上安装事件侦听器时没有问题?

Next, I gave unsafeWindow a try. It should not be needed. My userscript runs with @grant none and documentation (see here) says my script should run in the content scope.

如其 announcement 中所述,这对于 Greasemonkey 4 是错误的:

Due to the more limited abilities that the new extension system gives us, we are currently unable to make @grant none scripts work in the same way. Most importantly, they have a different connection to unsafeWindow. For the short term at least, it's a good idea to adopt cloneInto and exportFunction.

另请参阅其他问题Firefox doesn't respect Object.defineProperty() from a Greasemonkey script?

此更改解释了观察结果,但不知道为什么将侦听器添加到 window 起作用。