如何从对象URL获取文件或blob?

Bri*_*eud 104 javascript html5 blobs fileapi

我允许用户通过拖放和其他方法将图像加载到页面中.删除图像时,我正在使用URL.createObjectURL转换为对象URL来显示图像.我没有撤销网址,因为我重复使用它.

所以,当谈到时间来创建一个FormData对象,所以我可以让他们上传的形式,在它的形象之一,是有一些方法,然后我可以扭转这一目标URL回一个BlobFile因此我可以将其添加到FormData宾语?

Bri*_*eud 67

正如gengkev在上面的评论中提到的,看起来最好/唯一的方法是使用异步xhr2调用:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'blob:http%3A//your.blob.url.here', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
  if (this.status == 200) {
    var myBlob = this.response;
    // myBlob is now the blob that the object URL pointed to.
  }
};
xhr.send();
Run Code Online (Sandbox Code Playgroud)

更新(2018):对于可以安全使用ES5的情况,Joe在下面有一个更简单的基于ES5的答案.

  • 它在跨域请求的情况下不起作用. (23认同)
  • 你什么时候会有一个*objectURL*,它不是当前域和范围的本地? (19认同)
  • 下面没有“乔”。 (16认同)
  • "对象URL是指向磁盘上文件的URL." 根据定义,ObjectURL只能是本地的. (5认同)
  • 我做了同样的事情,但是用xhr找不到404.这是怎么回事? (4认同)
  • @BrianFreud"你什么时候会有一个不是当前域和范围本地的objectURL?" 在我的情况下,我试图给Amazon S3 blob一个不同的文件名,这是S3上没有扩展名的"guid".所以,就我而言,我正在使用跨域调用. (4认同)

小智 39

现代解决方案

let blob = await fetch(url).then(r => r.blob());
Run Code Online (Sandbox Code Playgroud)

url可以是对象url或普通url.

  • `let file = wait fetch(url).then(r => r.blob()).then(blobFile => new File([blobFile], "fileNameGoesHere", { type: "image/png" }))` 。末尾缺少一个括号 (7认同)
  • 而且,如果您想直接从Promise中获取文件,则可以如下生成文件。`let file =等待fetch(url).then(r => r.blob())。then(blobFile => new File([blobFile],“ fileNameGoesHere”,{类型:“ image / png”})` (4认同)
  • 真好 很高兴看到ES5使这种事情变得更简单。 (3认同)
  • 不幸的是,此解决方案不适用于Chrome。浏览器无法加载该URL。 (2认同)

Kai*_*ido 11

再次获取 Blob URL 的问题在于,这将创建 Blob 数据的完整副本,因此您将在内存中拥有两次,而不是仅在内存中拥有一次。对于大 Blob,这会很快耗尽您的内存使用量。

不幸的是,File API 不允许我们访问当前链接的 Blob,当然他们认为 Web 作者应该在创建时自行存储该 Blob,这是事实:

这里最好的方法是存储创建 blob:// URL 时使用的对象。

如果您担心这会阻止 Blob 被垃圾收集,那么您是对的,但是 blob:// URL 首先也是如此,直到您撤销它为止。因此,为自己保留一个指向该 Blob 的指针不会改变任何事情。

但对于那些不负责创建 blob:// URI 的人(例如,因为一个库创建了它),我们仍然可以通过覆盖默认的URL.createObjectURLURL.revokeObjectURL方法来自己填补该 API 漏洞,以便它们存储对传递的对象的引用。

请务必在调用生成 blob:// URI 的代码之前调用此函数。

// Adds an URL.getFromObjectURL( <blob:// URI> ) method
// returns the original object (<Blob> or <MediaSource>) the URI points to or null
(() => {
  // overrides URL methods to be able to retrieve the original blobs later on
  const old_create = URL.createObjectURL;
  const old_revoke = URL.revokeObjectURL;
  Object.defineProperty(URL, 'createObjectURL', {
    get: () => storeAndCreate
  });
  Object.defineProperty(URL, 'revokeObjectURL', {
    get: () => forgetAndRevoke
  });
  Object.defineProperty(URL, 'getFromObjectURL', {
    get: () => getBlob
  });
  const dict = {};

  function storeAndCreate(blob) {
    const url = old_create(blob); // let it throw if it has to
    dict[url] = blob;
    return url
  }

  function forgetAndRevoke(url) {
    old_revoke(url);
    try {
      if(new URL(url).protocol === 'blob:') {
        delete dict[url];
      }
    } catch(e){}
  }

  function getBlob(url) {
    return dict[url] || null;
  }
})();

//  Usage:
const blob = new Blob( ["foo"] );
const url = URL.createObjectURL( blob );
console.log( url );
const retrieved = URL.getFromObjectURL( url );
console.log( "retrieved Blob is Same Object?", retrieved === blob );
fetch( url ).then( (resp) => resp.blob() )
  .then( (fetched) => console.log( "fetched Blob is Same Object?", fetched === blob ) );
Run Code Online (Sandbox Code Playgroud)

另一个优点是它甚至可以检索MediaSource对象,而在这种情况下获取解决方案只会出错。


spe*_*edy 9

也许有人在使用React/Node/Axios时觉得这很有用.我react-dropzone在UI上使用它来实现我的Cloudinary图像上传功能.

    axios({
        method: 'get',
        url: file[0].preview, // blob url eg. blob:http://127.0.0.1:8000/e89c5d87-a634-4540-974c-30dc476825cc
        responseType: 'blob'
    }).then(function(response){
         var reader = new FileReader();
         reader.readAsDataURL(response.data); 
         reader.onloadend = function() {
             var base64data = reader.result;
             self.props.onMainImageDrop(base64data)
         }

    })
Run Code Online (Sandbox Code Playgroud)

  • 这适用于跨域请求吗?Twitter 视频具有 blob URL。我需要能够收集 blob URL 指向的 blob 对象。我在浏览器中使用 fetch api,这给了我这个错误——“拒绝连接到‘blob:https://twitter.com/9e00aec3-6729-42fb-b5a7-01f50be302fa’,因为它违反了以下内容安全策略指令:“connect-src`。你能不能提示一下我可能做错了什么/没有得到什么? (2认同)

小智 7

使用 fetch 例如如下:

 fetch(<"yoururl">, {
    method: 'GET',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + <your access token if need>
    },
       })
.then((response) => response.blob())
.then((blob) => {
// 2. Create blob link to download
 const url = window.URL.createObjectURL(new Blob([blob]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `sample.xlsx`);
 // 3. Append to html page
 document.body.appendChild(link);
 // 4. Force download
 link.click();
 // 5. Clean up and remove the link
 link.parentNode.removeChild(link);
})
Run Code Online (Sandbox Code Playgroud)

您可以粘贴到 Chrome 控制台进行测试。带有'sample.xlsx'的下载文件希望它可以帮助!


Mic*_*oyd 5

请参阅从 XHR 请求中获取 BLOB 数据,其中指出 BlobBuilder 在 Chrome 中不起作用,因此您需要使用:

xhr.responseType = 'arraybuffer';
Run Code Online (Sandbox Code Playgroud)