首页 > 解决方案 > 非法调用 addEventListener.call(xhr, "readystatechange", callback)

问题描述

在我的应用程序中,我们想要捕获 AJAX 请求和响应数据。为此,我们创建了围绕 XmlHttpReqeust 对象的包装器,如下示例代码所示。这工作正常,直到 angular(和许多其他 JS 框架)开始使用 addEventListener.call(xhr, "readystatechange", callback)。在这里,xhr 是我们包装类的对象。它在浏览器上引发“非法调用”错误。

这是我们的包装器(代理)实现的示例代码 -

(function (window) {

    var actualXHR = XMLHttpRequest;

    var XhrProxy = function () {
        this.xhr = new actualXHR();

        this.IsPostMethod;
        this.Method;
        this.Async;
        this.User;
        this.Pass;
        this.Url;

        this.sendData;

        function delegate(prop) {
            Object.defineProperty(this, prop, {
                get: function () {
                    return this.xhr[prop];
                },
                set: function (value) {
                     if (this.Async == undefined || this.Async || prop != "responseType") {
                        this.xhr[prop] = value;
                     }
                }
            });
        }

        delegate.call(this, 'timeout');
        delegate.call(this, 'responseType');
        delegate.call(this, 'withCredentials');
        delegate.call(this, 'onerror');
        delegate.call(this, 'onabort');
        delegate.call(this, 'onloadstart');
        delegate.call(this, 'onloadend');
        delegate.call(this, 'onprogress');
        delegate.call(this, 'readystatechange');
    };

    XhrProxy.prototype.open = function (method, url, async, user, pass) {
        var ctx = this;

        this.Method = method;
        this.Async = async;
        this.User = user;
        this.Pass = pass;
        this.Url = url;

        this.xhr.open.apply(this.xhr, arguments);

        this.xhr.onload = function (evt) {
            // Log response 
            if (ctx.onload)
                ctx.onload(evt);
        };
        this.xhr.onreadystatechange = function (evt) {
            if (ctx.onreadystatechange) {
                return ctx.onreadystatechange(evt);
            }
        };
    };

    XhrProxy.prototype.addEventListener = function (event, fn) {
        return this.xhr.addEventListener.apply(this.xhr, arguments);
    };

    XhrProxy.prototype.send = function (data) {
        this.sendData = data;
        // Log sendData 
        return this.xhr.send.apply(this.xhr, arguments);
    };
    XhrProxy.prototype.abort = function () {
        return this.xhr.abort.apply(this.xhr, arguments);
    };
    XhrProxy.prototype.getAllResponseHeaders = function () {
        return this.xhr.getAllResponseHeaders.apply(this.xhr, arguments);
    };

    XhrProxy.prototype.getResponseHeader = function (header) {
        return this.xhr.getResponseHeader.apply(this.xhr, arguments);
    };

    XhrProxy.prototype.setRequestHeader = function (header, value) {
        // Log headers
        return this.xhr.setRequestHeader.apply(this.xhr, arguments);
    };

    XhrProxy.prototype.overrideMimeType = function (mimetype) {
        return this.xhr.overrideMimeType.apply(this.xhr, arguments);
    };

    XhrProxy.interceptors = [];
    XhrProxy.addInterceptor = function (fn) {
        this.interceptors.push(fn);
    };

    window.XMLHttpRequest = XhrProxy;
})(window);

当任何消费者代码订阅readystatechange使用 addEventListener.call(xhr, "readystatechange", callback) 时,我们会在浏览器上收到“非法调用”错误。

这是获取“非法调用”的示例代码:

function callback() {
  // handle callback
}

var xhr = new XmlHttpRequest(); // it's object of wrapper class (XhrProxy)
xhr.open("GET", "someurl");

addEventListener.call(xhr, "readystatechange", callback); // <- this throws 'Illegal Invocation'

任何建议如何处理这种情况?

标签: javascriptdom-eventsaddeventlistener

解决方案


推荐阅读