【问题标题】:How to easily listen for xhr requests with Javascript?如何使用 Javascript 轻松监听 xhr 请求?
【发布时间】:2010-11-04 02:13:52
【问题描述】:

我正在开发一个 Firefox 扩展程序,我想知道页面何时发起 xhr 请求,我看到了一些代码,但它们非常大,有没有简单的示例可以实现这一点?

我正在测试这段代码:

function TracingListener() {
    //this.receivedData = [];
}

TracingListener.prototype =
{
    originalListener: null,
    receivedData: null,   // array for incoming data.

    onDataAvailable: function(request, context, inputStream, offset, count)
    {
        var binaryInputStream = CCIN("@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream");
        var storageStream = CCIN("@mozilla.org/storagestream;1", "nsIStorageStream");
        binaryInputStream.setInputStream(inputStream);
        storageStream.init(8192, count, null);

        var binaryOutputStream = CCIN("@mozilla.org/binaryoutputstream;1",
                "nsIBinaryOutputStream");

        binaryOutputStream.setOutputStream(storageStream.getOutputStream(0));

        // Copy received data as they come.
        var data = binaryInputStream.readBytes(count);
        //var data = inputStream.readBytes(count);
        this.receivedData.push(data);

        binaryOutputStream.writeBytes(data, count);
        this.originalListener.onDataAvailable(request, context,storageStream.newInputStream(0), offset, count);
    },

    onStartRequest: function(request, context) {
        this.receivedData = [];
        this.originalListener.onStartRequest(request, context);
    },

    onStopRequest: function(request, context, statusCode)
    {
        try 
        {
            request.QueryInterface(Ci.nsIHttpChannel);

            if (request.originalURI && piratequesting.baseURL == request.originalURI.prePath && request.originalURI.path.indexOf("/index.php?ajax=") == 0) 
            {

                var data = null;
                if (request.requestMethod.toLowerCase() == "post") 
                {
                    var postText = this.readPostTextFromRequest(request, context);
                    if (postText) 
                        data = ((String)(postText)).parseQuery();

                }
                var date = Date.parse(request.getResponseHeader("Date"));
                var responseSource = this.receivedData.join('');

                //fix leading spaces bug
                responseSource = responseSource.replace(/^\s+(\S[\s\S]+)/, "$1");

                piratequesting.ProcessRawResponse(request.originalURI.spec, responseSource, date, data);
            }
        } 
        catch (e) 
        {
            dumpError(e);
        }
        this.originalListener.onStopRequest(request, context, statusCode);
    },

    QueryInterface: function (aIID) {
        if (aIID.equals(Ci.nsIStreamListener) ||
            aIID.equals(Ci.nsISupports)) {
            return this;
        }
        throw Components.results.NS_NOINTERFACE;
    },
    readPostTextFromRequest : function(request, context) {
        try
        {
            var is = request.QueryInterface(Ci.nsIUploadChannel).uploadStream;
            if (is)
            {
                var ss = is.QueryInterface(Ci.nsISeekableStream);
                var prevOffset;
                if (ss)
                {
                    prevOffset = ss.tell();
                    ss.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
                }

                // Read data from the stream..
                var charset = "UTF-8";
                var text = this.readFromStream(is, charset, true);

                // Seek locks the file so, seek to the beginning only if necko hasn't read it yet,
                // since necko doesn't seek to 0 before reading (at lest not till 459384 is fixed).
                if (ss && prevOffset == 0) 
                    ss.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);

                return text;
            }
            else {
                dump("Failed to Query Interface for upload stream.\n");
            }
        }
        catch(exc)
        {
            dumpError(exc);
        }

        return null;
    },
    readFromStream : function(stream, charset, noClose) {

        var sis = CCSV("@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream");
        sis.setInputStream(stream);

        var segments = [];
        for (var count = stream.available(); count; count = stream.available())
            segments.push(sis.readBytes(count));

        if (!noClose)
            sis.close();

        var text = segments.join("");
        return text;
    }

}


hRO = {

    observe: function(request, aTopic, aData){
        try {
            if (typeof Cc == "undefined") {
                var Cc = Components.classes;
            }
            if (typeof Ci == "undefined") {
                var Ci = Components.interfaces;
            }
            if (aTopic == "http-on-examine-response") {
                request.QueryInterface(Ci.nsIHttpChannel);

                //if (request.originalURI && piratequesting.baseURL == request.originalURI.prePath) {
                   // var newListener = new TracingListener();
                    //request.QueryInterface(Ci.nsITraceableChannel);
                    //newListener.originalListener = request.setNewListener(newListener);
                //} GOOGLE FAILS TO LOAD IF I UNCOMMENT THIS
            } 
        } catch (e) {
            dump("\nhRO error: \n\tMessage: " + e.message + "\n\tFile: " + e.fileName + "  line: " + e.lineNumber + "\n");
        }
    },

    QueryInterface: function(aIID){
        if (typeof Cc == "undefined") {
            var Cc = Components.classes;
        }
        if (typeof Ci == "undefined") {
            var Ci = Components.interfaces;
        }
        if (aIID.equals(Ci.nsIObserver) ||
        aIID.equals(Ci.nsISupports)) {
            return this;
        }

        throw Components.results.NS_NOINTERFACE;

    },
};


var observerService = Cc["@mozilla.org/observer-service;1"]
    .getService(Ci.nsIObserverService);

observerService.addObserver(hRO,
    "http-on-examine-response", false);

但是在添加 newListener 时观察,如果我取消注释部分网站,如 Google(具有即时搜索功能)根本不会加载,我希望能够读取 onStopRequest 上的 responseSource,我尝试添加警报但它从来没有火灾,它会扰乱网站,就像我说的谷歌即时搜索发生的那样。

【问题讨论】:

    标签: javascript ajax xmlhttprequest dom-events


    【解决方案1】:

    在 javascript 中,您可以即时重新定义任何函数或对象。对于您的问题,您可以尝试以下方法:

    var original_xhr = XMLHttpRequest;
    XMLHttpRequest = function () {
       /* logic that notifies your plugin goes here */
        ...
       original_xhr();
       alert ("I redefined this function");
    

    【讨论】:

    • 这并没有捕捉到谷歌实时搜索功能的请求,你知道他们是否使用了不同于 xhr 的东西吗?
    • 是的,Google 使用了类似于 JSONP 的东西,它使用 document.write() 将脚本标签嵌入到页面中。因此,对于 google,您将覆盖 document.write() 函数。一些 JSONP 实现使用 document.appendChild(script_tag)。
    【解决方案2】:

    这是 Travis J Webb 解决方案的完整版本。只需将其放在 JS 或 HMTL 文件的顶部附近即可。

    (function(){
        var original_xhr = XMLHttpRequest;
        window.XMLHttpRequest = function () {
            /* logic that notifies your plugin goes here */
    
            original_xhr.apply(this, Array.prototype.slice.call(arguments));
            alert ("I redefined this function");
        }
    }());
    

    【讨论】:

    • 这并没有捕捉到谷歌实时搜索功能的请求,你知道他们是否使用了不同于 xhr 的东西吗?
    • 我用 FireFox 3.6.3 和 Firebug 运行了更新后的代码,它捕捉到了请求,但它也在 Google 的代码中显示了一个 javascript 错误。这让人相信还有一些改进的余地。
    猜你喜欢
    • 2014-12-20
    • 2012-12-07
    • 2017-02-19
    • 2020-02-14
    • 1970-01-01
    • 1970-01-01
    • 2022-06-17
    • 2013-03-15
    • 2010-10-31
    相关资源
    最近更新 更多