本文介绍了如何在Firefox中找到特定的缓存条目,并将它们变成一个File或Blob对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下情况:

用户可以将html内容粘贴到wysiwyg编辑器中。当粘贴的内容包含托管在其他域上的图像时,我希望将这些内容上传到我的服务器。现在唯一的方法是通过保存图像为...的上下文菜单手动下载,然后通过表单上载图像到服务器,并在编辑器中更新图像。



我必须解决这个客户端。

我正在开发一个可以自动执行处理。当然,我可以下载这些图像,将它们存储在硬盘上,然后使用FormData或者更好的pupload上传它们,但是由于内容显示在浏览器中,所以这似乎很笨拙,因为它必须已经下载并驻留在内存中。我想从内存中抓取图像文件,并告诉Firefox上传它们(能够使它们的Blob看起来就足够了)。然而,我正在MDN上的几个不同的缓存系统的API文档中失去希望,并且找不到任何示例代码来说明如何使用它们。我检查了访问缓存的其他插件的代码,但大多数没有注释,仍然相当隐秘。

你能指点一些示例代码来达到这个目的吗?最好的解决办法是,如果我可以请求从Firefox的特定网址,所以我可以在FormData中使用它,如果它不在缓存中的Firefox下载到内存,但如果它已经在那里,我只是直接得到它。

解决方案
Mozilla版本2 HTTP缓存的主文档位于。除了这个页面上的模糊之外,我能够理解这个新模式的唯一方法是通过查看每个对象的实际代码并反向引用几乎所有的东西。尽管我无法清楚地了解到底发生了什么,但我足够了解它的工作原理。在我看来,Mozilla应该花时间在创建一些简单的文档之前,先推出新的API。但是,我们得到他们给我们的东西,我想。



关于你的问题。我们假设想要上传图片的用户已经将此图片保存在缓存中的某处。为了能够将其从用户的缓存中提取出来,必须首先能够确定图像的URI,然后才能从缓存中明确地获取该图像的URI。为了简洁起见,我假设你已经有了这个部分。



关于新的HTTP Cache的一个重要的事情是,虽然它是所有基于回调,仍然可能只有一个单一的写作过程。虽然在你的例子中可能不需要写描述符,但是你仍然可以请求写访问,因为这会阻止其他进程(即浏览器)在完成之前修改/删除数据。对我来说,另一个侧面说明和一个很大的痛苦来源是,从内存缓存请求一个缓存条目将 ALWAYS 创建一个新的条目,覆盖任何预先存在的条目。你不应该需要这个,但是如果有必要的话,你可以从磁盘访问内存缓存(磁盘缓存是物理磁盘+内存缓存 - Mozilla逻辑)缓存,没有这个副作用。 b

一旦掌握了URI,就可以发出请求将其从缓存中提取出来。新的缓存系统完全基于回调。有一个关键对象,我们将需要为了能够获取缓存项的数据 - 。这是一个用户定义的对象,在请求缓存条目后处理响应。它必须有两个成员函数:onCacheEntryCheck(entry,appcache)和onCacheEntryAvilable(描述符,isnew,appcache,状态)。

下面是我的代码的一个简化例子这样一个对象:

  var cacheWaiter = {
//这个函数本质上告诉缓存服务是否我们想要
//这个缓存描述符。如果返回ENTRY_WANTED,则缓存描述符是
//传递给onCacheEntryAvailable()
onCacheEntryCheck:function(descriptor,appcache)
{
//首先,我们要确定缓存条目目前没有被写入
//所以我们可以确定当我们打开它时文件是完整的。
//如果预测的数据大小> dataSize,可能是它仍然在
//被缓存的过程中,我们将无法获得它的排他锁,它
//将是不完整的,所以我们不希望它现在。
if(descriptor.dataSize< descriptor.predictedDataSize)
//这将告诉nsICacheService在
//当前写入过程完成后再次调用这个函数缓存条目。
return Components.interfaces.nsICacheEntryOpenCallback.RECHECK_AFTER_WRITE_FINISHED;
}
catch(e){
//同样返回任何其他错误的相同值
return Components.interfaces.nsICacheEntryOpenCallback.RECHECK_AFTER_WRITE_FINISHED;
}
//如果没有发生异常并且expectedDataSize == dataSize,则告诉
// nsICacheService将描述符传递给this.onCacheEntryAvailable()
return Components.interfaces.nsICacheEntryOpenCallback .ENTRY_WANTED;
}

//一旦我们确定我们想要使用这个描述符(也就是完成
//下载并且我们想要读取它),它会被传递给这个函数
//我们可以用它来做我们想做的事情。
//此时我们将完全控制描述符,直到这个
//函数退出(或者,我相信这就是它的工作方式)
onCacheEntryAvailable:function(descriptor,isnew,appcache ,状态)
{
//在这个函数中,你可以做你的缓存描述符读取并将
//存储在一个Blob()中进行上传。我没有真正测试我把
//放在这里的代码,可能需要修改。
var cacheentryinputstream = descriptor.openInputStream(0);
var blobarray = new Array(0);
var buffer = new Array(1024);

(var i = descriptor.dataSize; i> 0; i - = 1024)
{
try {
cacheentryinputstream.read(buffer,1024) ;

catch(e){
//讨厌的NS_ERROR_WOULD_BLOCK异常似乎发生在我
//频繁。 Mozilla家伙不提供解决这个问题的方法,
//因为他们想要一个响应式的UI,不惜一切代价。所以,只要保持
//尝试,直到成功。
i + = 1024; (var j = 0; j {
blobarray.push(buffer.charAt(j));


}
}
}
var theblob = new Blob(blobarray);
//在这里做一个AJAX POST请求。





$ b现在回调对象已经设好了,缓存描述符。试试像这样:

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

//载入缓存服务
var cacheservice = Components.classes [@ mozilla.org/netwerk/cache-storage-service;1\"].getService(Components.interfaces.nsICacheStorageService );

//加载关于各种缓存的上下文信息
var {LoadContextInfo} = Components.utils.import(resource://gre/modules/LoadContextInfo.jsm,{})

//选择默认磁盘缓存。
var hdcache = cacheservice.diskCacheStorage(LoadContextInfo.default,true);

//请求一个缓存项目的URI。 OPEN_NORMALLY请求写入权限。
hdcache.asyncOpenURI(ioservice.newURI(theuri,null,null),,hdcache.OPEN_NORMALLY,cacheWaiter);

就实际获取URI而言,您可以为用户提供一个窗口,将图像放入或者可能只是粘贴图像的URL。然后,你可以做一个AJAX请求来获取图像(在用户由于某种原因实际上没有访问过该图像的情况下,它将被缓存)。然后,您可以使用该URL来获取上传的缓存条目。作为一个美学的触摸,你甚至可以显示图像的预览,但这有点超出了问题的范围。



如果您需要更多的说明,请放心要问!


I have the following scenario:

A user can paste html content in a wysiwyg editor. When that pasted content contains images which are hosted on other domains, I want these to be uploaded to my server. Right now the only way of doing that is manually downloading via "save image as..." context menu, then uploading the image to the server via a form and updating the images in the editor.

I have to solve this client side.

I'm working on a firefox addon that can automate the process. Of course I could download these images, store them on the harddrive and then upload them with FormData or better the pupload , but this seems clumsy as since the content is displayed in the browser, it must be downloaded already and reside somewhere in memory. I would like to grab the image files from memory and tell firefox to upload them (being able to make a Blob of them would suffice it seems).

However, I'm getting hopelessly lost in the API documentation for several different Caching systems on MDN and fail to find any example code of how to use them. I checked code of other addons that access the cache, but most is uncommented and still quite cryptic.

Can you point me to some sample code of what the recommended way would be to achieve this? The best possible solution would be if I can request the particular url from firefox so I can use it in FormData, and if it isn't in the cache firefox downloads to memory, but if it's already there I just get it directly.

解决方案

The master documentation for Mozilla's version 2 HTTP Cache is located here. Aside from the blurbs on this page, the only way I was able to make sense of this new scheme is by looking at the actual code for each object and back-referencing almost everything. Even though I wasn't able to get a 100% clear picture of what exactly was going on, I figured out enough to get it working. In my opinion, Mozilla should have taken the time to create some simple-terms documentation before they went ahead an pushed out the new API. But, we get what they give us I suppose.

On to your problem. We're assuming that the users who want to upload an image already have this image saved in their cache somewhere. In order to be able to pull it out of the user's cache for upload, you must first be able to determine the URI of the image before it can be pulled explicitly from the cache. For the sake of brevity, I'm going to assume that you already have this part figured out.

An important thing to note about the new HTTP Cache is that although it's all based off callbacks, there can still only ever be a single writing process. While in your example it may not be necessary to write to the descriptor, you should still request write access since that will prevent any other processes (i.e. the browser) from altering/deleting the data until you are done with it. Another side note and a source of a lot of pain for me was the fact that requesting a cache entry from the memory cache will ALWAYS created a new entry, overwriting any pre-existing entries. You shouldn't need this, but if it is necessary, you can access the memory cache from the disk (the disk cache is physical disk+memory cache -- Mozilla logic) cache without that side effect.

Once the URI is in hand, you can then make a request to pull it out of the cache. The new caching system is based completely on callbacks. There is one key object that we will need in order to be able to fetch the cache entry's data -- nsICacheEntryOpenCallback. This is a user-defined object that handles the response after a cache entry is requested. It must have two member functions: onCacheEntryCheck(entry, appcache) and onCacheEntryAvilable(descriptor, isnew, appcache, status).

Here is a cut-down example from my code of such an object:

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.
}

Now that the callback object is set up, we can actually do some requests for cache descriptors. Try something like this:

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);

As far as actually getting the URI, you could provide a window for a user to drag-and-drop an image into or perhaps just paste the URL of the image into. Then, you could do an AJAX request to fetch the image (in the case that the user hasn't actually visited the image for some reason, it would then be cached). You could then use that URL to then fetch the cache entry for upload. As an aesthetic touch, you could even show a preview of the image but that's a bit out of scope of the question.

If you need any more clarifications, please feel free to ask!

这篇关于如何在Firefox中找到特定的缓存条目,并将它们变成一个File或Blob对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-01 00:39