从 XHR 请求中获取 BLOB 数据
Posted
技术标签:
【中文标题】从 XHR 请求中获取 BLOB 数据【英文标题】:Getting BLOB data from XHR request 【发布时间】:2011-12-22 18:32:55 【问题描述】:var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://static.reddit.com/reddit.com.header.png', true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e)
if (this.status == 200)
var uInt8Array = new Uint8Array(this.response);
var byte3 = uInt8Array[4];
var bb = new WebKitBlobBuilder();
bb.append(xhr.response);
var blob = bb.getBlob('image/png');
var base64 = window.btoa(blob);
alert(base64);
;
xhr.send();
基本上,我在这里要做的是检索图像,并将其转换为 base64。
通过阅读 cmets here,它指出:
“当然。在获取资源作为 ArrayBuffer 后,从 它。一旦你有了它,你可以直接对文件/blob进行base64编码
window.btoa()
或FileReader.readAsDataURL()
。”
但是,blob
只是 [object blob]
,而我需要从图像中获取二进制文件,以便将其转换为 base64 并使用数据将其显示在 img 标签中。
有人知道如何实现吗?
提前谢谢你!
【问题讨论】:
我觉得你用 XHR 获取图像日期很奇怪......它甚至可以跨源工作吗?你的域名在 reddit 的 Access-Control-Allow-Origin 列表中吗? 这只是一个例子,实际的域是localhost 【参考方案1】:不要在 Chrome 中使用 BlobBuilder(在 OSX Chrome、Firefox 12、Safari 6、ios Chrome、iOS Safari 中测试):
ex1 : http://jsfiddle.net/malraux/xGUsu/(原理)
ex2:http://jsfiddle.net/xGUsu/78/(使用完整示例)
var xhr = new XMLHttpRequest();
xhr.open('GET', 'doodle.png', true);
xhr.responseType = 'arraybuffer';
// Process the response when the request is ready.
xhr.onload = function(e)
if (this.status == 200)
// Create a binary string from the returned data, then encode it as a data URL.
var uInt8Array = new Uint8Array(this.response);
var i = uInt8Array.length;
var binaryString = new Array(i);
while (i--)
binaryString[i] = String.fromCharCode(uInt8Array[i]);
var data = binaryString.join('');
var base64 = window.btoa(data);
document.getElementById("myImage").src="data:image/png;base64," + base64;
;
xhr.send();
注意:这段代码现在已经超过 7 年了。 虽然它在大多数浏览器中仍然可以正常工作,但这里是基于 @TypeError 建议的更新版本这只适用于更现代的浏览器iOS Safari 可能例外(可能支持也可能不支持responseType = 'blob'
- 请务必进行测试!):
var xhr = new XMLHttpRequest();
xhr.open('get', 'doodle.png', true);
// Load the data directly as a Blob.
xhr.responseType = 'blob';
xhr.onload = () =>
document.querySelector('#myimage').src = URL.createObjectURL(this.response);
;
xhr.send();
【讨论】:
xhr.responseType = 'blob' 没有在 chrome 中实现,它需要是一个数组缓冲区。见code.google.com/p/chromium/issues/detail?id=52486 谢谢!正是我想要的! Scott A,你是我眼中的神。确认它有效:) 有没有办法在不逐字节迭代数据的情况下做到这一点? @metadaddy:请注意,Blob 构造函数仅在最新的浏览器中可用。 @ScottA:好的,我之前没有意识到我们加载的文件是_not / is_different_frombase64
。图像在其他东西中,BLOB,“存储为单个实体的二进制数据集合”。所以你必须先转换成base64。明白了。【参考方案2】:
您可以获取Blob
并使用window.URL.createObjectURL
。这可以防止构建巨大的字符串并多次复制所有内容。
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://i.imgur.com/sBJOoTm.png', true);
xhr.responseType = 'blob';
xhr.onload = function(e)
if (this.status == 200)
var blob = this.response;
document.getElementById("myImage").src = window.URL.createObjectURL(blob);
;
xhr.onerror = function(e)
alert("Error " + e.target.status + " occurred while receiving the document.");
;
xhr.send();
<img id="myImage">
示例(相同代码):http://jsfiddle.net/ysangkok/sJxXk/86/。适用于 Firefox 和 Chrome 25+。以及除 Opera Mini 之外的所有其他浏览器:http://caniuse.com/#search=Blob
【讨论】:
Blob 构造函数仅在最新的浏览器中可用。例如,如果您必须支持 IE8 或 9,您将无法使用它。 @JanusTroelsen 如果您必须支持其中一种浏览器,这绝对没有任何意义(无论如何它都比 Firefox 使用的百分比更大)。 :-) 顺便说一句,IE10 仅 @JanusTroelsen 现在你在做一个政治论点,而不是一个实际的论点。对于我们这些必须在现实世界中谋生的人来说,非免费与免费不是一个选择,但如果你能够支持自己并坚持无情的立场,那么你就会拥有更多的力量。我个人有一个非常大的企业客户,直到 18 个月前还在内部使用 IE6,而现在使用的是 IE8。我无法告诉他们我只会支持 Chrome 或 Firefox,因为它们是免费软件。 @JanusTroelsen,为什么不直接将responseType
设置为blob,而不是通过arraybuffer
间接进行呢?见此代码:jsfiddle.net/RE9YJ
在 AngularJS 中,将 responseType: 'blob'
作为配置选项传递给 $http
。【参考方案3】:
XMLHttpRequest
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('GET', 'http://RestServiceURL-Returns Image', true);
xmlhttp.setRequestHeader('Content-type','application/x-www-form-urlencoded');
xmlhttp.responseType = 'arraybuffer/blob';
xmlhttp.send();
以 3 种方式创建 blob 图像。
window.URL.createObjectURL FileReader (caniuse)Base64String
xmlhttp.onload = function()
var blob = new Blob([this.response], type: 'image/png');
console.log(blob, blob.type, this.response, typeof this.response);
var image = document.getElementById('my-image');
1)image.src = window.URL.createObjectURL(blob);
2)var fileReader = new window.FileReader();
fileReader.readAsDataURL(blob);
fileReader.onloadend = function()
image.src = fileReader.result;
3)var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(this.response)));
image.src = 'data:image/png;base64,'+base64String;
;
将 ArrayBuffer 转换为 Blob 到 ArrayBuffer
1)var dataView = new DataView(arrayBuffer);
var blob = new Blob([dataView], type: mimeString );
2)fileReader.readAsArrayBuffer(blob);
var arrayBuffer;
fileReader.onload = function()
arrayBuffer = this.result;
;
【讨论】:
然后用于将文件保存在 IE 11 或 Egde 中:window.navigator.msSaveOrOpenBlob(blob, 'filename.pdf');【参考方案4】:与Janus Troelsen 建议的解决方案相同,并添加了承诺...
注意!使用createObjectURL时 - 不要忘记致电revokeObjectURL
// Load blob (promise)
function loadBlob( url )
return new Promise( (resolve, reject) =>
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onload = () => resolve(xhr.response);
xhr.onerror = () => reject(xhr.statusText);
xhr.send();
);
// Create image from blob (createObjectURL)
function imageFromBlob( blob )
const img = new Image();
img.onload = () => URL.revokeObjectURL(img.src);
img.src = URL.createObjectURL(blob);
return img;
// Create image from blob if loaded successfully
loadBlob('https://unsplash.it/960/540?random')
.then( blob =>
document.body.appendChild( imageFromBlob(blob) );
)
.catch( error =>
console.log('Could not load image');
)
// Alternate version adding promise to xhr
// if you like to trigger xhr.send() yourself
function xhrBlob(url)
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.promise = new Promise((resolve, reject) =>
xhr.onload = () => resolve(xhr.response);
xhr.onerror = () => reject(xhr.statusText);
);
xhr.load = ( onsuccess = () => , onerror = () => ) =>
xhr.promise.then(onsuccess).catch(onerror);
xhr.send();
return xhr;
return xhr;
// Using load callbacks
xhrBlob('https://unsplash.it/960/540?random')
.load(
// on sussess
blob =>
document.body.appendChild( imageFromBlob(blob) );
,
// on error
error =>
console.log('Could not load image');
);
// Using promise (delayed)
const image = xhrBlob('https://unsplash.it/960/540?random');
// Promise handlers
image.promise
.then( blob =>
document.body.appendChild( imageFromBlob(blob) );
)
.catch( error =>
console.log('Could not load image');
);
// Load image (will trigger promise handlers)
setTimeout(image.load, 3000);
img
width: 100%;
【讨论】:
以上是关于从 XHR 请求中获取 BLOB 数据的主要内容,如果未能解决你的问题,请参考以下文章
XHR 请求在 Scrapy 中失败,但在 python-requests 中有效