Monkey patch XMLHTTPRequest.onreadystatechange Monkey patch XMLHTTPRequest.onreadystatechange ajax ajax

Monkey patch XMLHTTPRequest.onreadystatechange


To monkey-patch XMLHttpRequests, you need to know how an AJAX request is generally constructed:

  1. Constructor invocation
  2. Preparation the request (setRequestHeader(), open())
  3. Sending the request (.send).

General-purpose patch

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

The previous assumed that onreadystatechange was assigned to the onreadystatechange handler. For simplicity, I didn't include the code for other events, such as onload. Also, I did not account for events added using addEventListener.

The previous patch runs for all requests. But what if you want to limit the patch to a specific request only? A request with a certain URL or async flag and a specific request body?

Conditional monkey-patch

Example: Intercepting all POST requests whose request body contains "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);

The main techniques used is the transparent rewrite using...

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

My examples are very basic, and can be extended to meet your exact wishes. That's up to you, however.


Assuming you can ignore 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 instancefunction 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;}


you can learn from Ajax-hook written by chinese!

it is a advanced js to enable Monkey patch XMLHTTPRequest