IndexedDB doesn't get the Blobs correctly if accessing from an index (WebKitBlobResource 1. Error)
Asked Answered
U

0

7

I have the full code you can copy at the end so that you can check this problem.

TL;DR: I'm using Safari 13.1 and after storing Blobs inside IndexedDB. If I close the browser I can only access those Blobs through the object store directly and not through some index of that object store. How can I use an index to recover the Blobs correctly?

May be I'm doing something wrong, but this seems to work in Google Chrome without any problems. I store a Blob inside an IndexedDB object store. My intention is to get it later, and use URL.createObjectURL(blob) to make the contents of the blob downloadable.

If I store the Blob and without closing the tab I try to recover it and create an URL, it works normally, and the URL works. Doesn't matter the way I get the Blob back (directly or through an index). In the example I only have one Blob. If I do objectStore.index('index1').getAll('foo') or objectStore.getAll() it works.

But if I restart Safari and open the webpage again, now I can only get the Blob directly from the objectStore (objectStore.getAll()). But if I try to get from an index (objectStore.index('idx').getAll(key)) the Blobs do not work. I get all the objects correctly and the rest of the info stored in the object store but the Blobs do not work, if I create an URL I get a WebKitBlobResource 1. Error.

Here's some example code.

If the database does not exist it creates it with an object store and an index, and stores a Blob inside. There are two buttons to generate the URL from that blob, both work normally. If one restarts Safari, then only one of those works (the one that get's the Blobs directly), the other, which uses the index to get from the database one gives back URLs that do not work.

<!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>
Unwilling answered 7/4, 2020 at 22:24 Comment(2)
any solution for this i have same problem.Saunder
Here’s some references to this problem: Error loading Blob to img in Safari HTML5 Video source as locally stored blob not workingClarita

© 2022 - 2024 — McMap. All rights reserved.