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


127

我允许用户通过拖放和其他方法将图像加载到页面中。放置图像时,我URL.createObjectURL用来转换为对象URL以显示图像。我没有撤消该URL,因为我确实重复使用了它。

因此,当需要创建一个FormData对象时,我可以允许他们上传其中包含这些图像之一的表单,是否可以通过某种方式将该对象URL反向转换为a BlobFile将其附加到a FormData目的?


别介意前两个评论-您需要做的只是向XMLHttpRequestBlob URL 发送一个。
gengkev 2012年

2
为什么不简单地将原始文件对象存储在某个地方,然后使用对象URL进行显示,并在表单提交时使用原始文件?
user764754

@ user764754,因为尝试获取用户正在上传的文件的URL显示为“ C:\ fakepath”
Malcolm Salvador

Answers:


86

现代解决方案:

let blob = await fetch(url).then(r => r.blob());

该URL可以是对象URL或普通URL。


3
真好 很高兴看到ES5使这种事情变得更简单。
BrianFreud

11
而且,如果您想直接从Promise中获取文件,则可以如下生成文件。 let file = await fetch(url).then(r => r.blob()).then(blobFile => new File([blobFile], "fileNameGoesHere", { type: "image/png" })
dbakiu

3
不幸的是,此解决方案不适用于Chrome。浏览器无法加载该URL。
waldgeist,

Waldgeist,您是否将其包装在createObjectUrl()中?
马特·弗莱彻

73

正如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();

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


19
什么时候会有一个objectURL不在当前域和范围内?
BrianFreud 2014年

4
我和上面一样,但是用xhr找不到404。这是怎么回事?
albert yu 2015年

请注意,一些浏览器(读旧的IE浏览器...),如果你需要处理那些看帖子stackoverflow.com/questions/17657184/...
mraxus

4
@BrianFreud“您何时会拥有不在当前域和范围本地的objectURL?” 就我而言,我试图给Amazon S3 Blob提供一个不同的文件名,该文件名目前是S3上的“引导”,没有扩展名。因此,就我而言,我正在使用跨域调用。
Wagner Bertolini Junior

6
“对象URL是指向磁盘上文件的URL。” 根据定义,ObjectURL只能是本地的。
BrianFreud

12

也许有人发现在使用React / Node / Axios时这很有用。我将此用于react-dropzoneUI上的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)
         }

    })

1
这对跨域请求有效吗?Twitter视频具有Blob URL。我需要能够收集blob URL指向的blob对象。我在浏览器中使用提取API,这给了我这个错误– Refused to connect to 'blob:https://twitter.com/9e00aec3-6729-42fb-b5a7-01f50be302fa' because it violates the following Content Security Policy directive: "connect-src 。您能否暗示我可能做错了/没做?
gdadsriver

我能够使用这种单行代码以blob作为数据属性来获得结果:const result = await axios.get(url,{responseType:“ blob”});
诺亚·斯塔尔


4

例如,使用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);
})

您可以粘贴在Chrome控制台上进行测试。带有“ sample.xlsx”下载的文件希望对您有所帮助!


我认为OP要求将blob网址转换为实际的文件/ blob,而不是相反。
Abhishek Ghosh

3

不幸的是,@ BrianFreud的答案不符合我的需求,我有一些不同的需求,我知道这不是@BrianFreud的问题的答案,但是我将其留在这里,因为很多人出于同样的需要来到这里。我需要类似“如何从URL获取文件或Blob?”之类的东西,当前的正确答案不符合我的需求,因为它不是跨域的。

我有一个网站使用Amazon S3 / Azure存储中的图像,并且在这里存储以uniqueidentifiers命名的对象:

范例:http://****.blob.core.windows.net/systemimages/bf142dc9-0185-4aee-a3f4-1e5e95a09bcf

其中一些图像应从我们的系统界面下载。为了避免通过我的HTTP服务器传递此流量,由于不需要访问任何安全性(域过滤除外),因此我决定在用户​​的浏览器上直接发出请求,并使用本地处理为该文件提供真实名称,延期。

为此,我使用了亨利·阿尔格斯的这篇出色文章:http : //www.henryalgus.com/reading-binary-files-using-jquery-ajax/

1.第一步:向jquery添加二进制支持

/**
*
* jquery.binarytransport.js
*
* @description. jQuery ajax transport for making binary data type requests.
* @version 1.0 
* @author Henry Algus <henryalgus@gmail.com>
*
*/

// use this transport for "binary" data type
$.ajaxTransport("+binary", function (options, originalOptions, jqXHR) {
    // check for conditions and support for blob / arraybuffer response type
    if (window.FormData && ((options.dataType && (options.dataType == 'binary')) || (options.data && ((window.ArrayBuffer && options.data instanceof ArrayBuffer) || (window.Blob && options.data instanceof Blob))))) {
        return {
            // create new XMLHttpRequest
            send: function (headers, callback) {
                // setup all variables
                var xhr = new XMLHttpRequest(),
        url = options.url,
        type = options.type,
        async = options.async || true,
        // blob or arraybuffer. Default is blob
        dataType = options.responseType || "blob",
        data = options.data || null,
        username = options.username || null,
        password = options.password || null;

                xhr.addEventListener('load', function () {
                    var data = {};
                    data[options.dataType] = xhr.response;
                    // make callback and send data
                    callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders());
                });

                xhr.open(type, url, async, username, password);

                // setup custom headers
                for (var i in headers) {
                    xhr.setRequestHeader(i, headers[i]);
                }

                xhr.responseType = dataType;
                xhr.send(data);
            },
            abort: function () {
                jqXHR.abort();
            }
        };
    }
});

2.第二步:使用此传输类型进行请求。

function downloadArt(url)
{
    $.ajax(url, {
        dataType: "binary",
        processData: false
    }).done(function (data) {
        // just my logic to name/create files
        var filename = url.substr(url.lastIndexOf('/') + 1) + '.png';
        var blob = new Blob([data], { type: 'image/png' });

        saveAs(blob, filename);
    });
}

现在,您可以使用想要创建的Blob,在我的情况下,我想将其保存到磁盘。

3.可选:使用FileSaver将文件保存在用户的计算机上

我已使用FileSaver.js将下载的文件保存到磁盘,如果需要完成此操作,请使用以下javascript库:

https://github.com/eligrey/FileSaver.js/

我希望这可以帮助有更多特定需求的其他人。


1
根据定义,ObjectURL是本地的。对象URL是指向磁盘上文件的URL。鉴于没有跨域objectURL之类的东西,因此您要组合两个不同的概念,因此使用给定的解决方案将遇到问题。
BrianFreud

1
@BrianFreud我知道这并不是这个问题的答案。但是我仍然认为这是一个很好的答案,因为我来这里寻找的是另一个问题“如何从URL获取文件或Blob?”的答案。如果您检查自己的答案,则会有10个反对的投票:“在跨域请求的情况下,此操作无效。'。因此,有十多人来到这里寻找。然后我决定将其留在这里。
Wagner Bertolini Junior

问题是,您的答案故意不回答该问题。普通URL和对象URL是完全不同的两件事。关于“在跨域请求的情况下不起作用。”上的否决数目,您是否认为这可以更好地解释为什么在这里实际上是不可能的,而是指向确实显示正常URL答案的地方,而不是而不是通过合并普通URL和对象URL来混淆此处的内容?
BrianFreud

@BrianFreud随时建议对我的答案进行编辑。我将研究这个主题,也许我误解了什么是“ objectURL”与“ object URL”……英语不是我的母语。我将对该主题进行研究以给出更好的答案。但是我认为是其他人来这里寻找不同的东西。我没有搜索“ objectURL”到达此处,这是我之前提到的重点。但是我也得到你。
Wagner Bertolini Junior

2

如果仍然在画布中显示文件,则还可以将画布内容转换为Blob对象。

canvas.toBlob(function(my_file){
  //.toBlob is only implemented in > FF18 but there is a polyfill 
  //for other browsers https://github.com/blueimp/JavaScript-Canvas-to-Blob
  var myBlob = (my_file);
})

2
请注意,这实际上并没有给您相同的回报原始文件;它正在动态制作新的图像文件。几年前,当我最后一次测试时,我发现至少在Chrome中,新的图像文件根本没有被压缩-我有1万个jpg变成了2.5 mb jpg。
BrianFreud
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.