尝试在 iOS 中存储 blob Safari 8 抛出 DataCloneError
Attempt to store blob in iOS Safari 8 throws DataCloneError
当我尝试存储 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 一样)?
我的代码 (适用于桌面 Chrome/Firefox 和 Chrome/Firefox Android):
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();
出于某些 奇怪 原因(这是一个错误),就像 iOS Safari 7 的 WebSQL 一样,您 不能 存储iOS Safari 8 上 IndexedDB 中的 BLOB。您必须将其转换为 base64,然后它才能正确存储。 (我重复一遍,这是一个错误)
因此,将代码更改为:
更改响应类型
xhr.responseType = "arraybuffer";
从 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");
从 IndexedDB 中检索后,将其转换回来:
//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);
当我尝试存储 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 一样)?
我的代码 (适用于桌面 Chrome/Firefox 和 Chrome/Firefox Android):
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();
出于某些 奇怪 原因(这是一个错误),就像 iOS Safari 7 的 WebSQL 一样,您 不能 存储iOS Safari 8 上 IndexedDB 中的 BLOB。您必须将其转换为 base64,然后它才能正确存储。 (我重复一遍,这是一个错误)
因此,将代码更改为:
更改响应类型
xhr.responseType = "arraybuffer";
从 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");
从 IndexedDB 中检索后,将其转换回来:
//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);