Javascript:覆盖 XMLHttpRequest.open()

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7775767/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 01:17:02  来源:igfitidea点击:

Javascript: Overriding XMLHttpRequest.open()

javascriptajaxxmlhttprequestoverriding

提问by Trevor

How would I be able to override the XMLHttpRequest.open()method and then catch and alter it's arguments?

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

I've already tried the proxy method but it didn't work, although removing the open over-rid when XMLHttpRequest()was called:

我已经尝试过代理方法,但它没有用,虽然XMLHttpRequest()在调用时删除了 open overrid :

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

回答by Esailija

You are not modifying the openmethod inherited by XMLHttpRequest objectsbut just adding a method to the XMLHttpRequest constructorwhich is actually never used.

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

I tried this code in facebook and I was able to catch the requests:

我在 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]
*/

So yeah the open method needs to be added to XMLHttpRequest prototype(window.XMLHttpRequest.prototype) not XMLHttpRequest constructor(window.XMLHttpRequest)

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

回答by rwilliams

I would give the xmlhttprequest projectat google code a look. It's a pretty good example of properly overriding the XMLHttpRequest object. The source can be seen here.

我会在 google 代码中查看xmlhttprequest 项目。这是正确覆盖 XMLHttpRequest 对象的一个​​很好的例子。来源可以在这里看到。

回答by Shadow2531

Use XMLHttpRequest.prototype.open instead.

使用 XMLHttpRequest.prototype.open 代替。

回答by Mark Dalsaso

Here is the approach I like to take; mind you, mastering the dark arts of XHR monkey patch is a bit of an art form.

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

Wrap the whole kit and caboodle in an IIFE. So start off with something like the following:

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

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

Any methods can be overridden using this general approach but the above scaffolding sets you up with a way to override (a.k.a monkey patch) both the open and send methods of XMLHttpRequest; in one neat utility function. Notice how the "base" methods (from the API's prototype object) are being fed into the IIFE and assigned to the var's "open" and "send", and safely scoped to the function block.

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

Now for the guts and what is key to persisting your monkey patch. Now again, this is how I do it and it works.

现在是胆量以及坚持猴子补丁的关键。再说一次,这就是我这样做的方式并且它有效。

The general pattern (all within the confines of the IIFE) is to:

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

1) replicate the method and its arguments, (the signature, in its entirety, per spec/prototype),

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

2) slip in your mod's, and

2)滑入你的模组,并且

3) apply your mod's to the XHR prototype property to ensure all XHR requests pass through your code.

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

So for example, "open" would look like:

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

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
};

Don't get hung up on the xhrOpenRequestUrl = url; line, this code is copied from an example where I needed the url for later processing. The key takeaway is "open.apply", it cements your tweaks into the XHR open method, if you're not familiar with the "apply" method or the "arguments" object, then now is a good time to learn what they do.

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

And similarly for the "send" 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
}

Again, the "apply" is critical and it must be done after all of your overrides. So putting it all together now...

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

(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)

Oh and one last thing, your monkey patch can, in turn, be monkey patched! To minimize this possibility the IIFE code should come after all of the other JS in the page. At least all JS that may be monkeying with XHR, but before any AJAX calls that you may be targeting. Also, and similarly, an XHR monkey patch can be injected via Chrome or Web Extension, and also override your override! HA!

哦,最后一件事,你的猴子补丁可以反过来被猴子补丁!为了尽量减少这种可能性,IIFE 代码应该在页面中的所有其他 JS 之后。至少所有可能会使用 XHR 的 JS,但在您可能针对的任何 AJAX 调用之前。此外,类似地,可以通过 Chrome 或 Web 扩展程序注入 XHR 猴子补丁,并覆盖您的覆盖!哈!

Hope that helps!

希望有帮助!