【问题标题】:Javascript: Overriding XMLHttpRequest.open()Javascript:覆盖 XMLHttpRequest.open()
【发布时间】:2011-12-08 05:07:00
【问题描述】:

我如何能够覆盖 XMLHttpRequest.open() 方法,然后捕获并更改它的参数?

我已经尝试过代理方法,但它不起作用,尽管在调用 XMLHttpRequest() 时删除了打开覆盖:

(function() {
    var proxied = window.XMLHttpRequest.open;
    window.XMLHttpRequest.open = function() {
        $('.log').html(arguments[0]);
        return proxied.apply(this, arguments);
    };
})();

【问题讨论】:

  • 你想要完成什么?
  • 我想更改 XMLHttpRequest.open() 的第二个参数,以便所有请求重新路由地址。
  • 你不能只为第二个参数使用一些“全局”变量。
  • 我也需要它们来处理任意请求,有些我可能无法控制。
  • 请注意,在扩展内容脚本中尝试此操作时,您将在不同的上下文中工作。您需要手动将脚本节点添加到包含您的覆盖的页面的头部

标签: javascript ajax xmlhttprequest overriding


【解决方案1】:

您并没有修改XMLHttpRequest objects 继承的open 方法,而只是在XMLHttpRequest constructor 中添加了一个实际上从未使用过的方法。

我在 facebook 中尝试了这段代码,我能够捕捉到请求:

(function() {
    var proxied = window.XMLHttpRequest.prototype.open;
    window.XMLHttpRequest.prototype.open = function() {
        console.log( arguments );
        return proxied.apply(this, [].slice.call(arguments));
    };
})();

/*
    ["POST", "/ajax/chat/buddy_list.php?__a=1", true]
    ["POST", "/ajax/apps/usage_update.php?__a=1", true]
    ["POST", "/ajax/chat/buddy_list.php?__a=1", true]
    ["POST", "/ajax/canvas_ticker.php?__a=1", true]
    ["POST", "/ajax/canvas_ticker.php?__a=1", true]
    ["POST", "/ajax/chat/buddy_list.php?__a=1", true]
*/

所以是的,需要将 open 方法添加到 XMLHttpRequest prototype (window.XMLHttpRequest.prototype) 而不是 XMLHttpRequest constructor (window.XMLHttpRequest)

【讨论】:

  • 这还能用吗?我无法从 chrome 扩展中运行它。网站目前是否使用 Fetch API?
  • @ngalstyan 我也做不到。你找到解决办法了吗?
  • 为什么需要[].slice.call 而不仅仅是arguments
【解决方案2】:

这是我喜欢采用的方法;请注意,掌握 XHR 猴子补丁的黑暗艺术是一种艺术形式。

将整个套件和一堆堆放在一个 IIFE 中。因此,请从以下内容开始:

(function(open, send) {
    //...overrides of the XHR open and send methods are now encapsulated within a closure
})(XMLHttpRequest.prototype.open, XMLHttpRequest.prototype.send)

可以使用这种通用方法覆盖任何方法,但是上面的脚手架为您提供了一种覆盖(又名猴子补丁)XMLHttpRequest 的 open 和 send 方法的方法;在一个简洁的效用函数中。请注意“基本”方法(来自 API 的原型对象)如何被输入 IIFE 并分配给 var 的“open”和“send”,并安全地限定在功能块的范围内。

现在来看看胆量和坚持猴子补丁的关键是什么。再说一次,这就是我的做法,而且效果很好。

一般模式(都在 IIFE 范围内)是:

1) 复制方法及其参数(签名,完整,每个规范/原型),

2) 滑入你的模组,并且

3) 将您的 mod 应用到 XHR 原型属性,以确保所有 XHR 请求都通过您的代码。

例如,“打开”看起来像:

XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
      xhrOpenRequestUrl = url;     // update request url, closure variable
      open.apply(this, arguments); // reset/reapply original open method
};

不要挂断 xhrOpenRequestUrl = url;行,此代码是从我需要 url 以供以后处理的示例中复制的。关键点是“open.apply”,它将您的调整巩固到 XHR open 方法中,如果您不熟悉“apply”方法或“arguments”对象,那么现在是学习它们的好时机.

同样对于“发送”方法...

XMLHttpRequest.prototype.send = function(data) {
  //...what ever code you need, i.e. capture response, etc.
  if (this.readyState == 4 && this.status >= 200 && this.status < 300) {
    xhrSendResponseUrl = this.responseURL;
    responseData = this.data;  // now you have the data, JSON or whatever, hehehe!
  }
  send.apply(this, arguments); // reset/reapply original send method
}

同样,“应用”很关键,必须在所有覆盖之后完成。所以现在把它们放在一起......

(function(open, send) {

   // Closure/state var's
   var xhrOpenRequestUrl;  // captured in open override/monkey patch
   var xhrSendResponseUrl; // captured in send override/monkey patch
   var responseData;       // captured in send override/monkey patch

   //...overrides of the XHR open and send methods are now encapsulated within a closure

   XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
      xhrOpenRequestUrl = url;     // update request url, closure variable
      open.apply(this, arguments); // reset/reapply original open method
   };

   XMLHttpRequest.prototype.send = function(data) {

      //...what ever code you need, i.e. capture response, etc.
      if (this.readyState == 4 && this.status >= 200 && this.status < 300) {
         xhrSendResponseUrl = this.responseURL;
         responseData = this.data;  // now you have the data, JSON or whatever, hehehe!
      }
      send.apply(this, arguments); // reset/reapply original send method
   }

})(XMLHttpRequest.prototype.open, XMLHttpRequest.prototype.send)

哦,最后一件事,您的猴子补丁可以反过来进行猴子补丁!为了尽量减少这种可能性,IIFE 代码应该位于页面中所有其他 JS 之后。至少所有可能与 XHR 发生冲突的 JS,但在您可能针对的任何 AJAX 调用之前。此外,同样地,可以通过 Chrome 或 Web 扩展注入 XHR 猴子补丁,并覆盖您的覆盖!哈!

希望对您有所帮助!

【讨论】:

    【解决方案3】:

    我会在 google 代码中查看 xmlhttprequest project。这是正确覆盖 XMLHttpRequest 对象的一个​​很好的例子。源码可见here

    【讨论】:

    【解决方案4】:

    改用 XMLHttpRequest.prototype.open。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-30
      • 2010-12-16
      • 2021-01-26
      • 1970-01-01
      • 2011-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多