2015-01-08 38 views
4

我有以下場景:如何在firefox中查找特定的緩存條目並將它們轉換爲File或Blob對象?

用戶可以將html內容粘貼到wysiwyg編輯器中。當粘貼的內容包含託管在其他域上的圖像時,我希望將這些內容上傳到我的服務器。目前,唯一的方法是通過「保存圖像作爲...」上下文菜單手動下載,然後通過表單將圖像上載到服務器,並在編輯器中更新圖像。

我必須解決這個客戶端。

我正在開發一個可以自動化進程的firefox插件。當然,我可以下載這些圖像,將它們存儲在硬盤上,然後使用FormData或更好的pupload上傳它們,但這似乎很笨拙,因爲內容顯示在瀏覽器中,它必須已經下載並駐留在內存中。我想從內存中抓取圖像文件,並告訴Firefox上傳它們(能夠使它們的Blob看起來足夠了)。

但是,我正在MDN上的幾個不同的緩存系統的API文檔中失去希望,並且無法找到如何使用它們的任何示例代碼。我檢查了訪問緩存的其他插件的代碼,但大多數插件沒有註釋,仍然很隱晦。

你能指點我一些什麼建議的方式來實現這個示例代碼?最好的解決方案是,如果我可以從firefox請求特定的url,那麼我可以在FormData中使用它,並且如果它不在緩存中,那麼firefox會下載到內存中,但如果它已經存在,我就直接獲取它。

+0

這位用戶在mozillazine,Githlar上,有很多緩存經驗,如果我有任何問題緩存相關,他告訴我由他來運行它。在mzine上發佈這個話題,併發送給這個人一條消息,這是一個很棒的問題,我希望看到一個答案:) – Noitidart

+0

感謝您的提示,我支持tor防火牆,我無法訪問mozilla zine論壇,因爲它說ip禁止...你有任何聯繫這個用戶的方式嗎? – nus

+1

你好nus,我有幾個問題:你所見即所得的編輯器就像一個web應用程序,對嗎?如果是這樣的話,你不需要插件來做到這一點,只需要一些服務器端腳本下載圖像,把它們放在某個地方,並用本地URL替換遠程URL的所有實例。但是,如果您必須使用擴展名......那麼我仍然試圖通過這個擴展。我可以告訴你,與我正在嘗試做的事情相比,這將是相當容易的。但我同意,Mozilla的Cache v2文檔非常糟糕。 –

回答

4

Mozilla版本2 HTTP緩存的主文檔位於here。除了這個頁面上的模糊之外,我能夠理解這個新方案的唯一方法是通過查看每個對象的實際代碼並反向引用幾乎所有的東西。儘管我無法清楚地瞭解到底發生了什麼,但我足夠了解它的工作原理。在我看來,Mozilla應該花時間在繼續推出新API之前創建一些簡單條款的文檔。但是,我們可以得到他們給我們的東西。

解決您的問題。我們假設想要上傳圖片的用戶已將此圖片保存在緩存中的某處。爲了能夠將其從用戶的緩存中取出用於上載,必須先能夠確定圖像的URI,然後才能從緩存中明確提取圖像的URI。爲了簡潔起見,我假設你已經找到了這個部分。

有關新HTTP緩存的一個重要事項是,儘管它都基於回調,但仍然只能有一個單獨的寫入過程。儘管在您的示例中可能不需要寫入描述符,但您仍然可以請求寫入權限,因爲這會阻止任何其他進程(即瀏覽器)在完成之前更改/刪除數據。另一個方面的說明和對我來說很痛苦的一個原因是,從內存緩存請求緩存條目將始終總是創建一個新條目,覆蓋任何預先存在的條目。你不應該需要這個,但是如果有必要的話,你可以從磁盤訪問內存緩存(磁盤緩存是物理磁盤+內存緩存 - Mozilla邏輯)緩存,沒有這種副作用。

一旦掌握了URI,就可以發出請求將其從緩存中取出。新的緩存系統完全基於回調。爲了能夠獲取緩存條目的數據,我們需要一個關鍵對象 - nsICacheEntryOpenCallback。這是一個用戶定義的對象,用於在請求緩存條目後處理響應。它必須有兩個成員函數:onCacheEntryCheck(entry,appcache)和onCacheEntryAvilable(描述符,isnew,appcache,status)。

這裏是我的這種對象的代碼刪節例如:

var cacheWaiter = { 
    //This function essentially tells the cache service whether or not we want 
    //this cache descriptor. If ENTRY_WANTED is returned, the cache descriptor is 
    //passed to onCacheEntryAvailable() 
    onCacheEntryCheck: function(descriptor, appcache) 
    { 
    //First, we want to be sure the cache entry is not currently being written 
    //so that we can be sure that the file is complete when we go to open it. 
    //If predictedDataSize > dataSize, chances are it's still in the process of 
    //being cached and we won't be able to get an exclusive lock on it and it 
    //will be incomplete, so we don't want it right now. 
    try{ 
     if(descriptor.dataSize < descriptor.predictedDataSize) 
     //This tells the nsICacheService to call this function again once the 
     //currently writing process is done writing the cache entry. 
     return Components.interfaces.nsICacheEntryOpenCallback.RECHECK_AFTER_WRITE_FINISHED; 
    } 
    catch(e){ 
     //Also return the same value for any other error 
     return Components.interfaces.nsICacheEntryOpenCallback.RECHECK_AFTER_WRITE_FINISHED; 
    } 
    //If no exceptions occurred and predictedDataSize == dataSize, tell the 
    //nsICacheService to pass the descriptor to this.onCacheEntryAvailable() 
    return Components.interfaces.nsICacheEntryOpenCallback.ENTRY_WANTED; 
    } 

    //Once we are certain we want to use this descriptor (i.e. it is done 
    //downloading and we want to read it), it gets passed to this function 
    //where we can do what we wish with it. 
    //At this point we will have full control of the descriptor until this 
    //function exits (or, I believe that's how it works) 
    onCacheEntryAvailable: function(descriptor, isnew, appcache, status) 
    { 
    //In this function, you can do your cache descriptor reads and store 
    //it in a Blob() for upload. I haven't actually tested the code I put 
    //here, modifications may be needed. 
    var cacheentryinputstream = descriptor.openInputStream(0); 
    var blobarray = new Array(0); 
    var buffer = new Array(1024);  

    for(var i = descriptor.dataSize; i > 0; i -= 1024) 
    { 
     try{ 
     cacheentryinputstream.read(buffer, 1024); 
     } 
     catch(e){ 
     //Nasty NS_ERROR_WOULD_BLOCK exceptions seem to happen to me 
     //frequently. The Mozilla guys don't provide a way around this, 
     //since they want a responsive UI at all costs. So, just keep 
     //trying until it succeeds. 
     i += 1024; 
     } 
     for(var j = 0; j < 1024; j++) 
     { 
     blobarray.push(buffer.charAt(j)); 
     } 
    } 
    } 
    var theblob = new Blob(blobarray); 
    //Do an AJAX POST request here. 
} 

現在回調對象設置,我們實際上可以做緩存描述一些請求。嘗試是這樣的:

var theuri = "http://www.example.com/image.jpg"; 

//Load the cache service 
var cacheservice = Components.classes["@mozilla.org/netwerk/cache-storage-service;1"].getService(Components.interfaces.nsICacheStorageService); 

//Load context info about the various caches 
var {LoadContextInfo} = Components.utils.import("resource://gre/modules/LoadContextInfo.jsm",{}) 

//Select the default disk cache. 
var hdcache = cacheservice.diskCacheStorage(LoadContextInfo.default, true); 

//Request a cache entry for the URI. OPEN_NORMALLY requests write access. 
hdcache.asyncOpenURI(ioservice.newURI(theuri, null, null), "", hdcache.OPEN_NORMALLY, cacheWaiter); 

至於實際得到的URI,你可以爲用戶拖動和刪除一個圖像到或者只是圖像的URL粘貼到提供一個窗口。然後,您可以執行AJAX請求來獲取圖像(如果用戶由於某種原因未實際訪問該圖像,則會被緩存)。然後,您可以使用該URL來獲取上傳的緩存條目。作爲一種美感,你甚至可以展示圖像的預覽,但這有點超出了問題的範圍。

如果您需要更多的說明,請隨時詢問!

+0

非常感謝。這是一個令人難以置信的答案。我認爲這會爲我節省幾天的工作時間,也可能讓其他人工作。是的,我擁有這些網址,我通過粘貼事件從tinymce中抓取。現在我已經實現了一種解決方法,只需將它們下載到臨時文件夾,然後使用File API上傳它們即可。我甚至可以將File對象傳遞給plupload,所以它只是很好地集成到了網站中。我想我仍然需要,以防萬一緩存項不存在,但我會嘗試將它保存在緩存中而不是臨時目錄中。 – nus

+0

當我開始整合時,我將使用您發佈的代碼創建一個門面類,它將隱藏我的應用程序代碼中的mozilla api。基本上,對於我的應用程序,我想讓它看起來像告訴Firefox:將此遠程位置的文件上傳到此服務器。 (我認爲有些瀏覽器允許用戶將url傳入html文件輸入元素,但是如果我沒有錯誤,Firefox就不會)。也許我會做一些JavaScript庫,它允許這樣做。然後對於插件來說,它只是設置文件輸入值的問題。 – nus

+0

我非常忙,所以在我回到這之前幾個星期,但是當我更好地理解事情時,我也會嘗試改進那些神祕的mdn文檔。非常感謝你的幫助! – nus

相關問題