7

猴子如何修补XMLHTTPRequest'sonreadystatechange功能。我正在尝试添加一个函数,当从页面发出的每个 ajax 请求都返回时将调用该函数。

我知道这听起来是个糟糕的主意,但用例却很奇特。我想将某个 SDK 与控制台 (jqconsole) 一起使用,但在控制台中显示 ajax 调用的状态和结果,而无需修改外部 SDK。

我看过这篇文章,里面有很多信息,但是没有关于猴子修补回调的内容,这似乎超出了我的 JavaScript 技能。

PS 不能使用 jQuery,因为它只支持从 jQuery 而不是XMLHTTPRequests直接从这里进行的 ajax 调用。

4

3 回答 3

12

对于monkey-patch XMLHttpRequest,你需要知道一个AJAX请求一般是如何构造的:

  1. 构造函数调用
  2. 准备请求 ( setRequestHeader(), open())
  3. 发送请求 ( .send)。

通用补丁

(function(xhr) {
    function banana(xhrInstance) { // Example
        console.log('Monkey RS: ' + xhrInstance.readyState);
    }
    // Capture request before any network activity occurs:
    var send = xhr.send;
    xhr.send = function(data) {
        var rsc = this.onreadystatechange;
        if (rsc) {
            // "onreadystatechange" exists. Monkey-patch it
            this.onreadystatechange = function() {
                banana(this);
                return rsc.apply(this, arguments);
            };
        }
        return send.apply(this, arguments);
    };
})(XMLHttpRequest.prototype);

前面假设onreadystatechange已分配给onreadystatechange处理程序。为简单起见,我没有包含其他事件的代码,例如onload. 此外,我没有考虑使用addEventListener.

之前的补丁适用于所有请求。但是,如果您只想将补丁限制为特定请求怎么办?具有特定 URL 或异步标志和特定请求正文的请求?

有条件的猴子补丁

示例:拦截POST请求正文中包含“TEST”的所有请求

(function(xhr) {
    function banana(xhrInstance) { // Example
        console.log('Monkey RS: ' + xhrInstance.readyState);
    }
    // 
    var open = xhr.open;
    xhr.open = function(method, url, async) {
        // Test if method is POST
        if (/^POST$/i.test(method)) {
            var send = this.send;
            this.send = function(data) {
                // Test if request body contains "TEST"
                if (typeof data === 'string' && data.indexOf('TEST') >= 0) {
                    var rsc = this.onreadystatechange;
                    if (rsc) {
                        // Apply monkey-patch
                        this.onreadystatechange = function() {
                            banana(this);
                            return rsc.apply(this, arguments);
                        };
                    }
                }
                return send.apply(this, arguments);
            };
        }
        return open.apply(this, arguments);
    };
})(XMLHttpRequest.prototype);

使用的主要技术是使用透明重写...

var original = xhr.method; 
xhr.method = function(){
    /*...*/;
    return original.apply(this, arguments);
};

我的示例非常基本,可以扩展以满足您的确切愿望。然而,这取决于你。

于 2012-09-25T08:31:44.400 回答
0

假设你可以忽略 IE ......

//Totally untested code, typed at the SO <textarea>... but the concept *should* work, let me know if it doesn't.
var OldXMLRequest = XMLHttpRequest;

// Create a new instance
function XMLHttpRequest() {
  var ajax = new OldXMLRequest();

  // save old function
  var f = ajax.onreadystatechange;
  ajax.onreadystatechange = function() {
    console.log("Whatever!");
    f(); // Call the old function
  }
  return ajax;
}
于 2012-09-25T04:39:42.233 回答
0

你可以学习中文写的Ajax-hook

它是一个高级 js 来启用 Monkey 补丁 XMLHTTPRequest

于 2017-06-03T14:39:06.493 回答