我允许用户通过拖放和其他方法将图像加载到页面中。删除图像时,我使用URL.createObjectURL
转换为对象URL以显示图像。我没有撤销网址,因为我重复使用它。
因此,当需要创建一个FormData
对象以便我们允许他们上传包含其中一个图像的表单时,我是否可以通过某种方式将该对象URL反转回{ {1}}或Blob
我可以将其附加到File
对象吗?
答案 0 :(得分:62)
正如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的答案。
答案 1 :(得分:21)
现代解决方案:
let blob = await fetch(url).then(r => r.blob());
URL可以是对象URL或普通URL。
答案 2 :(得分:8)
在使用React / Node / Axios时,也许有人觉得这很有用。我在UI上使用了这个用于我的Cloudinary图像上传功能{/ 1}}。
react-dropzone
答案 3 :(得分:4)
请参阅Getting BLOB data from XHR request,其中指出BlobBuilder无法在Chrome中运行,因此您需要使用:
xhr.responseType = 'arraybuffer';
答案 4 :(得分: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);
})
答案 5 :(得分:1)
不幸的是@BrianFreud的答案不符合我的需要,我有一点不同的需求,我知道这不是@BrianFreud的问题的答案,但是我把它留在这里是因为很多人来到这里因为我的一样需要。我需要“如何从URL获取文件或blob?”这样的内容,当前正确的答案不符合我的需求,因为它不是跨域的。
我有一个网站,它使用来自Amazon S3 / Azure存储的图像,并在那里存储以uniqueidentifiers命名的对象:
示例:http://****.blob.core.windows.net/systemimages/bf142dc9-0185-4aee-a3f4-1e5e95a09bcf
部分图片应从我们的系统界面下载。 为了避免通过我的HTTP服务器传递此流量,因为此对象不需要访问任何安全性(除了域过滤),我决定在用户的浏览器上直接请求并使用本地处理为文件提供真实姓名和扩展
为了实现这一点,我使用了Henry Algus的这篇精彩文章: 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/
我希望这可以帮助其他有更多特定需求的人。
答案 6 :(得分:1)
以如下所示为例:
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”下载的文件,希望对您有所帮助!
答案 7 :(得分:0)
再次获取 Blob URL 的问题在于,这将创建 Blob 数据的副本,因此不是在内存中只保存一次,而是两次。对于大 Blob,这可能会很快消耗您的内存。
不幸的是,File API 没有让我们访问当前链接的 Blob,他们当然认为网络作者应该在创建时自己存储 Blob,这是真的:
这里最好是存储您在创建 blob:// URL 时使用的对象。如果您担心这会阻止 Blob 被垃圾收集,您是对的,但是 blob 也是如此:// URL 放在首位,直到您撤销它。因此,让自己指向那个 Blob 的指针不会改变任何事情。
但是对于那些不负责创建 blob:// URI 的人(例如,因为库创建了它),我们仍然可以通过覆盖默认的 URL.createObjectURL 来自己填补该 API 漏洞。 em> 和 URL.revokeObjectURL 方法,以便它们存储对传递对象的引用。
请务必在调用生成 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 ) );
另一个优点是它甚至可以检索 MediaSource 对象,而在这种情况下获取解决方案只会出错。