从 XHR 请求中获取 BLOB 数据

IT技术 javascript webkit blob xmlhttprequest
2021-02-04 22:57:32
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。

从阅读这里的评论来看,它指出:

“当然。在将资源作为 ArrayBuffer 获取后,从中创建一个 blob。一旦有了它,您就可以直接对文件/blob 进行 base64 编码 window.btoa()FileReader.readAsDataURL().”

但是,blob只是[object blob],而我需要从图像中获取二进制文件,以便我可以将其转换为 base64 并使用数据将其显示在 img 标签中。

有谁知道如何实现这一目标?

先感谢您!

4个回答

不要在 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
2021-03-19 22:57:32
有没有办法在不逐字节迭代数据的情况下做到这一点?
2021-03-28 22:57:32
@ScottA:好的,我之前没有意识到我们加载的文件 is_not / is_different_from base64图像在别的东西中,BLOB,“作为单个实体存储的二进制数据的集合”。所以你必须先转换成base64。知道了。
2021-03-28 22:57:32
@metadaddy:请注意,Blob 构造函数仅在最新浏览器中可用。
2021-04-03 22:57:32
谢谢!正是我要找的!Scott A,你是我眼中的神。确认它有效:)
2021-04-05 22:57:32

您可以获取 aBlob并使用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

@JanusTroelsen 现在你在进行政治争论,而不是实际的争论。对于我们这些不得不在现实世界中谋生的人来说,非自由与自由不是一种选择,但是如果您能够养活自己并坚持无情的立场,那么您将拥有更多的力量。我个人有一个非常大的企业客户,它在 18 个月前还在内部使用 IE6,现在使用 IE8。我无法告诉他们我只会支持 Chrome 或 Firefox,因为它们是免费软件。
2021-03-13 22:57:32
@JanusTroelsen,为什么不直接将responseTypeblob设置为 blob 而不是通过 间接进行arraybuffer请参阅此代码:jsfiddle.net/RE9YJ
2021-03-17 22:57:32
Blob 构造函数仅在最新的浏览器中可用。例如,如果您必须支持 IE8 或 9,您将无法使用它。
2021-03-30 22:57:32
@JanusTroelsen 如果您必须支持其中一种浏览器,这绝对没有任何意义(无论如何,它的百分比都比 Firefox 使用的要大)。:-) 顺便说一句,IE10 仅 < 4%,因此您实际上是在争论开发人员应该完全忽略 IE,如果您查看 NetApplications 而不是 StatCounter,那么 IE 8+9 是桌面的 44%。话虽如此,您的 Blob 解决方案不适用于:OS X 上的 Safari 6.0.2、OS X 上的 Firefox 12 或 iPhone 4s 上的 Safari 和 Chrome。
2021-04-02 22:57:32
在 AngularJS 中,{responseType: 'blob'}作为配置选项传入$http.
2021-04-04 22:57:32

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 图像。

  • 窗口.URL。创建对象URL
  • FileReader ( caniuse )
  • Base64字符串

    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');
2021-03-26 22:57:32

Janus Troelsen建议的解决方案相同,并添加了Promise......

笔记! 使用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%;
}