Monkey patch XMLHTTPRequest.onreadystatechange

后端 未结 3 1100
半阙折子戏
半阙折子戏 2020-12-16 04:35

How would go about monkey patching the XMLHTTPRequest\'s onreadystatechange function. I\'m trying to add a function that would be called when every

相关标签:
3条回答
  • 2020-12-16 05:16

    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.

    0 讨论(0)
  • 2020-12-16 05:23

    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 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;
    }
    
    0 讨论(0)
  • 2020-12-16 05:27

    you can learn from Ajax-hook written by chinese!

    it is a advanced js to enable Monkey patch XMLHTTPRequest

    0 讨论(0)
提交回复
热议问题