如果从索引访问,IndexedDB 无法正确获取 Blob(WebKitBlobResource 1. 错误)

Man*_*uel 5 javascript safari blob indexeddb

我有完整的代码,你可以在最后复制,这样你就可以检查这个问题。

特尔;博士: 我使用的是 Safari 13.1,并且在将 Blob 存储在 IndexedDB 中之后。如果我关闭浏览器,我只能直接通过对象存储访问这些 Blob,而不能通过该对象存储的某些索引访问。如何使用索引正确恢复 Blob?

可能是我做错了什么,但这似乎在谷歌浏览器中没有任何问题。我在 IndexedDB 对象存储中存储了一个 Blob。我的意图是稍后获取它,并使用 URL.createObjectURL(blob) 使 blob 的内容可下载。

如果我存储 Blob 并且没有关闭选项卡,我会尝试恢复它并创建一个 URL,它可以正常工作,并且 URL 可以工作。我取回 Blob 的方式无关紧要(直接或通过索引)。在示例中,我只有一个 Blob。如果我这样做objectStore.index('index1').getAll('foo')objectStore.getAll()它有效。

但是如果我重新启动 Safari 并再次打开网页,现在我只能直接从 objectStore ( objectStore.getAll()) 中获取 Blob 。但是,如果我尝试从索引 (objectStore.index('idx').getAll(key) ) 中则 Blob 不起作用。我正确获取了所有对象,其余信息存储在对象存储中,但 Blob 不起作用,如果我创建一个 URL,我会得到一个 WebKitBlobResource 1. 错误。

这是一些示例代码。

如果数据库不存在,它会使用对象存储和索引创建它,并在其中存储一个 Blob。有两个按钮可以从该 blob 生成 URL,它们都可以正常工作。如果重新启动 Safari,则只有其中一个有效(直接获取 Blob 的那个),另一个使用索引从数据库中获取的 URL 返回不起作用的 URL。

<!DOCTYPE html>
<html>
<head>
  <title>Bug retrieving blobs from database</title>
</head>
<body>

<button id="clear-btn">Clear</button>
<button id="retrieve-working">Retrieve working</button>
<button id="retrieve-not-working">Retrieve not working</button>

<script>
  document.getElementById('clear-btn').addEventListener('click', () => {
    db.close();
    indexedDB.deleteDatabase('bug');
  });
  document.getElementById('retrieve-working').addEventListener('click', async () => {
    const objs = await getAllWithoutIndex();
    console.log('Objects retrieved without index which result in a correct URL', URL.createObjectURL(objs[0].blob));
  });
  document.getElementById('retrieve-not-working').addEventListener('click', async () => {
    const objs = await getAll('foo-1');
    console.log('Objects retrieved', URL.createObjectURL(objs[0].blob));
  });

  let db, created = false;
  const dbrequest = indexedDB.open('bug');
  dbrequest.addEventListener('upgradeneeded', (e) => {
    const db = e.target.result;
    const objs = db.createObjectStore('objectstore', {keyPath: 'id', autoIncrement: true});
    objs.createIndex('index1', 'foo', {unique: false});
    created = true;
    console.log('Database did not exist, we just created it');
  });
  dbrequest.addEventListener('success', async (e) => {
    db = e.target.result;

    if (created) {
      console.log('Storing one object');
      const obj1 = await store({
        foo: 'foo-1',
        blob: new Blob([0], {type: 'text/plain'}),
      }).catch(console.error);
      console.log('Object stored', obj1);
    }
    console.log('Database already exists, now you can get the objects');
  });

  function store(obj) {
    return new Promise((resolve, reject) => {
      const transaction = db.transaction('objectstore', 'readwrite');
      const objectStore = transaction.objectStore('objectstore');
      const request = objectStore.put(obj);
      request.addEventListener('success', (e) => obj.id = e.target.result);
      transaction.addEventListener('complete', () => resolve(obj));
    });
  }

  function getAll(foo) {
    return new Promise((resolve, reject) => {
      const objectStore = db.transaction('objectstore', 'readonly').objectStore('objectstore');
      const request = objectStore.index('index1').getAll(foo);
      request.addEventListener('success', (e) => resolve(e.target.result));
    });
  }

  function getAllWithoutIndex() {
    return new Promise((resolve, reject) => {
      const objectStore = db.transaction('objectstore', 'readonly').objectStore('objectstore');
      const request = objectStore.getAll();
      request.addEventListener('success', (e) => resolve(e.target.result));
    });
  }
</script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)