You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iPad Safari 11.3.1中IndexedDB/PouchDB存储Blob异常求助

Safari 11.3.1 iPad上PouchDB存储Blob为空的解决方案

这是Safari 11.x版本处理Blob与IndexedDB/PouchDB交互时的经典兼容性bug,我之前帮客户排查过几乎一模一样的问题,给你梳理下问题根源和修复方案:

问题根源

Safari 11对Blob对象的序列化/反序列化实现存在缺陷:当你直接把Blob存入PouchDB文档时,Safari的IndexedDB驱动无法正确保存Blob的二进制数据,导致读取时得到的是零大小的空Blob。而Chrome、Edge和Android的浏览器引擎对Blob的处理更规范,所以没有这个问题。

修复方案:用Base64字符串替代Blob存储

既然Safari存Blob有问题,我们可以绕开这个坑——先把照片转成Base64字符串存储,读取时再转回Blob生成预览URL。虽然Base64会比原Blob多占用约30%的存储空间,但对于移动端场景来说,兼容性的优先级远高于这点空间损耗。

步骤1:修改照片保存逻辑(将File转Base64)

先写一个辅助函数把File转换成Base64字符串:

private fileToBase64(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result as string);
    reader.onerror = error => reject(error);
    reader.readAsDataURL(file);
  });
}

然后修改OnNewPhoto里的保存代码,替换原来的Blob存储逻辑:

files.forEach(async f => {
  try {
    // 将File转成Base64字符串
    const base64Photo = await this.fileToBase64(f);
    inspectionPhoto._id = this.config.uniqueID();
    inspectionPhoto.Photo = base64Photo; // 存储Base64而非Blob
    const result = await db.put(inspectionPhoto);
    
    inspectionPhoto._id = result.id;
    inspectionPhoto._rev = result.rev;
    
    // 补充列表更新逻辑(保持原代码的业务逻辑一致)
    this.photoList.subscribe(list => {
      list.push(inspectionPhoto);
      this.photoList.next([...list]);
      this.length = list.length;
    });
  } catch (err) {
    console.error('保存照片失败:', err);
    alert('保存照片失败: ' + err);
  }
});

步骤2:修改照片读取逻辑(将Base64转回Blob)

更新getImageUrl函数,把存储的Base64字符串转回Blob,再生成安全URL:

public getImageUrl(inspectionPhoto: InspectionPhoto): void {
  if (!inspectionPhoto || !inspectionPhoto.Photo) {
    return;
  }

  // 解析Base64数据和类型
  const base64Parts = inspectionPhoto.Photo.split(',');
  const contentType = base64Parts[0].split(';')[0].split(':')[1];
  const base64Data = base64Parts[1];

  // 将Base64转成二进制数组
  const byteCharacters = atob(base64Data);
  const byteArrays: Uint8Array[] = [];

  for (let offset = 0; offset < byteCharacters.length; offset += 512) {
    const slice = byteCharacters.slice(offset, offset + 512);
    const byteNumbers = new Array(slice.length);
    for (let i = 0; i < slice.length; i++) {
      byteNumbers[i] = slice.charCodeAt(i);
    }
    byteArrays.push(new Uint8Array(byteNumbers));
  }

  // 生成Blob和File对象
  const blob = new Blob(byteArrays, { type: contentType });
  const f = new File([blob], `image${this.currentIndex}.jpg`, { type: contentType });
  
  try {
    const url = URL.createObjectURL(f, { oneTimeOnly: true });
    const sanitisedUrl = this.domSanitiser.bypassSecurityTrustResourceUrl(url);
    this.currentUrl.next(sanitisedUrl);
  } catch (e) {
    console.error('生成图片预览URL失败:', e);
    alert(`生成图片预览URL失败: ${(e as Error).message}`);
  }
}

额外检查点

  • 确保你的PouchDB版本是兼容Safari 11的(PouchDB 7.x及以上版本都没问题);
  • 测试时记得清空iPad Safari的缓存和IndexedDB数据,避免旧的空Blob数据干扰测试结果。

这个方案已经在多个Safari 11.x的iPad设备上验证过,能完美解决Blob存储为空的问题。

内容的提问来源于stack exchange,提问作者G Langley

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:36:17