尝试跟踪 Firefox 中未完成的 AJAX 请求的数量

发布于 2024-10-06 21:35:06 字数 3123 浏览 3 评论 0原文

我正在使用 Selenium 来测试 Web 应用程序,并且不允许修改应用程序的 javascript 代码。我试图通过使用 GreaseMonkey 覆盖 XMLHttpRequest.send 来跟踪未完成的 AJAX 请求的数量。新的 send() 基本上将包装设置为 onreadystatechange 回调的内容,检查readyState,适当增加或减少计数器,并调用原始回调函数。

我遇到的问题似乎是权限问题,因为如果我只是浏览到普通 Firefox 浏览器中的页面,打开 Firebug 并粘贴以下代码,它似乎工作正常:

document.ajax_outstanding = 0;
if (typeof XMLHttpRequest.prototype.oldsend != 'function') {
    XMLHttpRequest.prototype.oldsend = XMLHttpRequest.prototype.send;
    XMLHttpRequest.prototype.send = function() {
        console.log('in new send');
        console.log('this.onreadystatechange = ' + this.onreadystatechange);
        this.oldonreadystatechange = this.onreadystatechange;
        this.onreadystatechange = function() {
            if (this.readyState == 2) {
                /* LOADED */
                document.ajax_outstanding++;
                console.log('set ajax_outstanding to ' + document.ajax_outstanding);
            }
            this.oldonreadystatechange.handleEvent.apply(this, arguments);
            if (this.readyState == 4) {
                /* COMPLETED */
                document.ajax_outstanding--;
                console.log('set ajax_outstanding to ' + document.ajax_outstanding);
            }
        };
        this.oldsend.apply(this, arguments);
    };
}

现在,如果我使用稍作修改的版本GreaseMonkey 用户脚本中的该片段如下所示:

unsafeWindow.document.ajax_outstanding = 0;
if (typeof unsafeWindow.XMLHttpRequest.prototype.oldsend != 'function') {
    unsafeWindow.XMLHttpRequest.prototype.oldsend = unsafeWindow.XMLHttpRequest.prototype.send;
    unsafeWindow.XMLHttpRequest.prototype.send = function() {
        GM_log('in new send');
        GM_log('this.onreadystatechange = ' + this.onreadystatechange);
        this.oldonreadystatechange = this.onreadystatechange;
        this.onreadystatechange = function() {
            if (this.readyState == 2) {
                /* LOADED */
                unsafeWindow.document.ajax_outstanding++;
                GM_log('set ajax_outstanding to ' + unsafeWindow.document.ajax_outstanding);
            }
            this.oldonreadystatechange.handleEvent.apply(this, arguments);
            if (this.readyState == 4) {
                /* COMPLETED */
                unsafeWindow.document.ajax_outstanding--;
                GM_log('set ajax_outstanding to ' + unsafeWindow.document.ajax_outstanding);
            }
        };
        this.oldsend.apply(this, arguments);
    };
}

我转到一个页面,执行一些导致 AJAX 请求的操作,我在 javascript 错误控制台中收到以下消息:

http://www.blah.com/gmscripts/overrides: in new send
uncaught exception: [Exception... "Illegal value" nsresult: "0x80070057 (NS_ERROR_ILLEGAL_VALUE)" location: "JS frame :: file:///tmp/customProfileDir41e7266f56734c97a2ca02b1f7f528e1/extensions/%7Be4a8a97b-f2ed-450b-b12d-ee082ba24781%7D/components/greasemonkey.js :: anonymous :: line 372" data: no]

因此,在尝试访问时似乎会抛出异常this.onreadystatechange

据推测,这是由于沙盒环境造成的。 任何帮助将不胜感激。我不依赖于这个解决方案,所以欢迎任何其他建议来完成我需要的事情。只是我已经尝试了其他几种,这似乎是最有希望的。要求是我需要确保在readyState变为4并且onreadystatechange回调完成执行之后计数器变为0。

I am using Selenium to test a web application and am not allowed to modify the application's javascript code. I am trying to track the number of outstanding AJAX requests by using GreaseMonkey to override XMLHttpRequest.send. The new send() will basically wrap what was set as the onreadystatechange callback, check the readyState, incrementing or decrementing the counter as appropriate, and calling the original callback function.

The problem that I'm having appears to be a privilege issue because if I just browse to a page in a normal firefox browser, open firebug and paste in the following code, it seems to work fine:

document.ajax_outstanding = 0;
if (typeof XMLHttpRequest.prototype.oldsend != 'function') {
    XMLHttpRequest.prototype.oldsend = XMLHttpRequest.prototype.send;
    XMLHttpRequest.prototype.send = function() {
        console.log('in new send');
        console.log('this.onreadystatechange = ' + this.onreadystatechange);
        this.oldonreadystatechange = this.onreadystatechange;
        this.onreadystatechange = function() {
            if (this.readyState == 2) {
                /* LOADED */
                document.ajax_outstanding++;
                console.log('set ajax_outstanding to ' + document.ajax_outstanding);
            }
            this.oldonreadystatechange.handleEvent.apply(this, arguments);
            if (this.readyState == 4) {
                /* COMPLETED */
                document.ajax_outstanding--;
                console.log('set ajax_outstanding to ' + document.ajax_outstanding);
            }
        };
        this.oldsend.apply(this, arguments);
    };
}

Now if I use a slightly modified version of that snippet from within a GreaseMonkey user script like so:

unsafeWindow.document.ajax_outstanding = 0;
if (typeof unsafeWindow.XMLHttpRequest.prototype.oldsend != 'function') {
    unsafeWindow.XMLHttpRequest.prototype.oldsend = unsafeWindow.XMLHttpRequest.prototype.send;
    unsafeWindow.XMLHttpRequest.prototype.send = function() {
        GM_log('in new send');
        GM_log('this.onreadystatechange = ' + this.onreadystatechange);
        this.oldonreadystatechange = this.onreadystatechange;
        this.onreadystatechange = function() {
            if (this.readyState == 2) {
                /* LOADED */
                unsafeWindow.document.ajax_outstanding++;
                GM_log('set ajax_outstanding to ' + unsafeWindow.document.ajax_outstanding);
            }
            this.oldonreadystatechange.handleEvent.apply(this, arguments);
            if (this.readyState == 4) {
                /* COMPLETED */
                unsafeWindow.document.ajax_outstanding--;
                GM_log('set ajax_outstanding to ' + unsafeWindow.document.ajax_outstanding);
            }
        };
        this.oldsend.apply(this, arguments);
    };
}

and I go to a page, do something that causes an AJAX request, I get the following message in the javascript error console:

http://www.blah.com/gmscripts/overrides: in new send
uncaught exception: [Exception... "Illegal value" nsresult: "0x80070057 (NS_ERROR_ILLEGAL_VALUE)" location: "JS frame :: file:///tmp/customProfileDir41e7266f56734c97a2ca02b1f7f528e1/extensions/%7Be4a8a97b-f2ed-450b-b12d-ee082ba24781%7D/components/greasemonkey.js :: anonymous :: line 372" data: no]

So it appears to be throwing the exception when trying to access this.onreadystatechange

Presumably, this is due to the sandboxed environment.
Any help would be greatly appreciated. I am not tied to this solution, so any other suggestions for doing what I need are welcome. It's just that I've tried several others and this seems to be the most promising. The requirement is that I need to make sure that the counter gets to 0 after the readyState goes to 4 and the onreadystatechange callback has finished execution.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

记忆里有你的影子 2024-10-13 21:35:06

我自己做了一些东西: http://jsfiddle.net/rudiedirkx/skp28agx/ (更新22 2015 年 1 月)

脚本(应该在其他任何事情之前运行):

(function(xhr) {
    xhr.active = 0;
    var pt = xhr.prototype;
    var _send = pt.send;
    pt.send = function() {
        xhr.active++;
        this.addEventListener('readystatechange', function(e) {
            if ( this.readyState == 4 ) {
                setTimeout(function() {
                    xhr.active--;
                }, 1);
            }
        });
        _send.apply(this, arguments);
    }
})(XMLHttpRequest);

以及 jsFiddle 的测试脚本:

window.onload = function() {
    var btn = document.querySelector('button'),
        active = btn.querySelector('span');

    btn.onclick = function() {
        // jQuery for easy ajax. `delay` is a jsFiddle argument
        // to keep some requests active longer.
        jQuery.post('/echo/json/', {
            delay: Math.random() * 3,
        });
    };

    updateActive();

    function updateActive() {
        active.textContent = XMLHttpRequest.active;
        requestAnimationFrame(updateActive);
    }
};

它会在每个动画帧(每秒约 60 次)更新按钮中的计数器,与 AJAX 请求分开。无论您做什么,无论点击速度有多快、点击次数多多,几秒钟后计数器都应该始终为 0。

I've made something myself: http://jsfiddle.net/rudiedirkx/skp28agx/ (updated 22 Jan 2015)

The script (should run before anything else):

(function(xhr) {
    xhr.active = 0;
    var pt = xhr.prototype;
    var _send = pt.send;
    pt.send = function() {
        xhr.active++;
        this.addEventListener('readystatechange', function(e) {
            if ( this.readyState == 4 ) {
                setTimeout(function() {
                    xhr.active--;
                }, 1);
            }
        });
        _send.apply(this, arguments);
    }
})(XMLHttpRequest);

And the jsFiddle's test script:

window.onload = function() {
    var btn = document.querySelector('button'),
        active = btn.querySelector('span');

    btn.onclick = function() {
        // jQuery for easy ajax. `delay` is a jsFiddle argument
        // to keep some requests active longer.
        jQuery.post('/echo/json/', {
            delay: Math.random() * 3,
        });
    };

    updateActive();

    function updateActive() {
        active.textContent = XMLHttpRequest.active;
        requestAnimationFrame(updateActive);
    }
};

It updates the counter in the button every animation frame (~ 60 times per second), separate from the AJAX requests. Whatever you do, however fast and much you click it, the counter should always end up at 0 after a few seconds.

梦在深巷 2024-10-13 21:35:06

我最终使用了以下内容:

unsafeWindow.document.ajax_outstanding = 0;
if (typeof unsafeWindow.XMLHttpRequest.prototype.oldsend != 'function') {
    unsafeWindow.XMLHttpRequest.prototype.oldsend = unsafeWindow.XMLHttpRequest.prototype.send;
    unsafeWindow.XMLHttpRequest.prototype.send = function() {
        unsafeWindow.XMLHttpRequest.prototype.oldsend.apply(this, arguments);
        this.addEventListener('readystatechange', function() {
            if (this.readyState == 2) {
                /* LOADED */
                unsafeWindow.document.ajax_outstanding++;
                console.log('set ajax_outstanding to ' + unsafeWindow.document.ajax_outstanding);
            } else if (this.readyState == 4) {
                /* COMPLETED */
                unsafeWindow.document.ajax_outstanding--;
                console.log('set ajax_outstanding to ' + unsafeWindow.document.ajax_outstanding);
            }
        }, false);
    };
}

I ended up using the following:

unsafeWindow.document.ajax_outstanding = 0;
if (typeof unsafeWindow.XMLHttpRequest.prototype.oldsend != 'function') {
    unsafeWindow.XMLHttpRequest.prototype.oldsend = unsafeWindow.XMLHttpRequest.prototype.send;
    unsafeWindow.XMLHttpRequest.prototype.send = function() {
        unsafeWindow.XMLHttpRequest.prototype.oldsend.apply(this, arguments);
        this.addEventListener('readystatechange', function() {
            if (this.readyState == 2) {
                /* LOADED */
                unsafeWindow.document.ajax_outstanding++;
                console.log('set ajax_outstanding to ' + unsafeWindow.document.ajax_outstanding);
            } else if (this.readyState == 4) {
                /* COMPLETED */
                unsafeWindow.document.ajax_outstanding--;
                console.log('set ajax_outstanding to ' + unsafeWindow.document.ajax_outstanding);
            }
        }, false);
    };
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文