2010-11-04 93 views
5

我正在做一個Firefox擴展,我想知道一個頁面何時啓動一個xhr請求,我看到了一些代碼,但它們非常大,有沒有簡單的示例來實現這一點?如何輕鬆在javascript中監聽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時注意觀察,如果我取消對部分網站如谷歌(即時搜索功能)不會加載在所有的,我希望能夠閱讀onStopRequest的responseSource,我試着添加一個警報,但它永遠不會觸發,它會弄亂網站,就像我說它發生在谷歌即時搜索。

回答

6

在javascript中,您可以即時重新定義任何函數或對象。對於你的問題,你可以嘗試這樣的事情:

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

希望有所幫助。

-tjw

+0

這沒有趕上谷歌實時搜索功能的請求,你知道他們是否使用不同於xhr的東西嗎? – gtilx 2010-11-04 18:54:27

+2

是的,Google使用類似於JSONP的東西,它使用document.write()將腳本標籤嵌入到頁面中。所以對於google,你會覆蓋document.write()函數。一些JSONP實現使用document.appendChild(script_tag)。 – 2010-11-05 00:01:16

3

以下是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"); 
    } 
}()); 
+0

這沒有趕上谷歌實時搜索功能的請求,你知道他們是否使用不同於xhr的東西嗎? – gtilx 2010-11-04 18:53:52

+0

我用FireFox 3.6.3和Firebug運行了更新後的代碼,它發現了這個請求,但它也在Google的代碼中顯示了一個javascript錯誤。這導致了相信有一些改進空間。 – Eric 2010-11-04 22:16:34