首页 文章

尝试在iOS Safari 8中存储blob会引发DataCloneError

提问于
浏览
2

当我尝试存储blob(通过 XMLHttpRequest GET 请求检索时,iOS 8.4上的Safari会抛出错误:

DataCloneError: DOM IDBDatabase Exception 25: The data being stored could
not be cloned by the internal structured cloning algorithm

这发生在我的代码和这个例子中:http://robnyman.github.io/html5demos/indexeddb/

这是导致我的代码(和上面的示例)失败的行:

//This throws the error
var put = transaction.objectStore("elephants").put(blob, "image");

有没有解决这个问题? blob是否需要首先进行base64编码(就像你必须使用WebSQL一样)?

My CODE (适用于桌面Chrome / Firefox和Android上的Chrome / Firefox):

var xhr = new XMLHttpRequest();
var blob;

//Get the Video
xhr.open( "GET", "test.mp4", true );

//Set as blob
xhr.responseType = "blob";

//Listen for blob
xhr.addEventListener("load", function () {
        if (xhr.status === 200) {
            blob = xhr.response;

            //Start transaction
            var transaction = db.transaction(["Videos"], "readwrite");

            //IT FAILS HERE
            var put = transaction.objectStore("Videos").put(blob, "savedvideo");

        }
        else {
            console.log("ERROR: Unable to download video." );
        }
}, false);

xhr.send();

1 回答

  • 3

    由于一些奇怪的原因(它是_2877141_的WebSQL,你在iOS Safari 8上存储了一个BLOB在IndexedDB中 . 你必须将它转换为base64然后它将存储而没有错误 . (我再说一遍,这是一个bug)

    所以,将代码更改为:

    Change response type

    xhr.responseType = "arraybuffer";
    

    Storing in database after retrieving from XMLHttpRequest

    //We'll make an array of unsigned ints to convert
    var uInt8Array = new Uint8Array(xhr.response);
    var i = uInt8Array.length;
    var binaryString = new Array(i);
    while (i--)
    {
        //Convert each to character
        binaryString[i] = String.fromCharCode(uInt8Array[i]);
    }
    
    //Make into a string
    var data = binaryString.join('');
    
    //Use built in btoa to make it a base64 encoded string
    var base64 = window.btoa(data);
    
    //Now we can save it
    var transaction = db.transaction(["Videos"], "readwrite");
    var put = transaction.objectStore("Videos").put(base64, "savedvideo");
    

    After retrieving form the IndexedDB, convert it back:

    //Convert back to bytes
    var data = atob( event.target.result );
    
    //Make back into unsigned array
    var asArray = new Uint8Array(data.length);
    
    for( var i = 0, len = data.length; i < len; ++i ) 
    {
        //Get back as int
        asArray[i] = data.charCodeAt(i);    
    }
    
    //Make into a blob of proper type
    var blob = new Blob( [ asArray.buffer ], {type: "video/mp4"} );
    
    //Make into object url for video source
    var videoURL = URL.createObjectURL(blob);
    

相关问题