IndexedDB неправильно получает BLOB-объекты при доступе из индекса (WebKitBlobResource 1. Ошибка) - PullRequest
1 голос
/ 08 апреля 2020

У меня есть полный код, который вы можете скопировать в конце, чтобы вы могли проверить эту проблему.

TL; DR: Я использую Safari 13.1 и после сохранения Капли внутри IndexedDB. Если я закрою браузер, то получу доступ к этим BLOB-объектам только через хранилище объектов напрямую, а не через какой-то индекс этого хранилища объектов. Как я могу использовать индекс для правильного восстановления BLOB-объектов?

Может быть, я делаю что-то не так, но, похоже, это работает в Google Chrome без проблем. Я храню Blob внутри хранилища объектов IndexedDB. Я собираюсь получить его позже и использовать URL.createObjectURL (blob), чтобы сделать содержимое BLOB-файла доступным для загрузки.

Если я сохраняю BLOB-объект и не закрываю вкладку, я пытаюсь восстановить его и создать URL-адрес. , он работает нормально, и URL работает. Не имеет значения, каким образом я получаю блоб обратно (напрямую или через индекс). В примере у меня есть только один Blob. Если я сделаю objectStore.index('index1').getAll('foo') или objectStore.getAll(), это сработает.

Но если я перезапущу Safari и снова открою веб-страницу, теперь я могу получить только BLOB-объект непосредственно из objectStore (objectStore.getAll()). Но если я пытаюсь получить из индекса (objectStore.index('idx').getAll(key)), BLOB-объекты не работают. Я получаю все объекты правильно, а остальная информация хранится в хранилище объектов, но BLOB-объекты не работают, если я создаю URL-адрес, я получаю WebKitBlobResource 1. Ошибка.

Вот пример кода.

Если база данных не существует, она создает ее с хранилищем объектов и индексом и сохраняет внутри BLOB-объект. Есть две кнопки для генерации URL из этого блоба, обе работают нормально. Если один перезапускает Safari, то работает только одна из них (та, которая получает двоичные объекты напрямую), другая, которая использует индекс для получения из базы данных, возвращает 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>
...