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

Safari内容脚本调用chrome.storage.local.set报错,求可行解决方案

Safari 扩展内容脚本存储配额问题的解决方案

问题核心

在部分Safari移动端设备/版本中,内容脚本调用await chrome.storage.local.set({ arr: [] })触发配额超限错误(即使本地存储为空),但扩展的非内容脚本页面可正常使用chrome.storage.local;同时Safari的Service Worker稳定性差,无法依赖其处理存储操作,需寻找内容脚本可直接使用的可靠替代方案。

最优方案:内容脚本直接使用IndexedDB存储

IndexedDB在Safari内容脚本中完全可用,且不存在chrome.storage.local的配额异常问题,是当前场景下的最优选择。以下是具体实现方案:

1. 封装IndexedDB操作工具类

为简化使用,封装通用的IndexedDB操作模块,覆盖初始化、设置、获取、删除数据的核心功能:

class ExtensionStorage {
  constructor(dbName = 'ExtensionDB', storeName = 'localStore') {
    this.dbName = dbName;
    this.storeName = storeName;
    this.db = null;
  }

  // 初始化数据库连接
  async init() {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.dbName, 1);
      
      request.onupgradeneeded = (e) => {
        this.db = e.target.result;
        if (!this.db.objectStoreNames.contains(this.storeName)) {
          this.db.createObjectStore(this.storeName);
        }
      };

      request.onsuccess = (e) => {
        this.db = e.target.result;
        resolve();
      };

      request.onerror = (e) => {
        reject(e.target.error);
      };
    });
  }

  // 存储数据
  async set(key, value) {
    if (!this.db) await this.init();
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction(this.storeName, 'readwrite');
      const store = transaction.objectStore(this.storeName);
      const request = store.put(value, key);

      request.onsuccess = () => resolve();
      request.onerror = () => reject(request.error);
    });
  }

  // 获取数据
  async get(key) {
    if (!this.db) await this.init();
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction(this.storeName, 'readonly');
      const store = transaction.objectStore(this.storeName);
      const request = store.get(key);

      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(request.error);
    });
  }

  // 删除数据
  async delete(key) {
    if (!this.db) await this.init();
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction(this.storeName, 'readwrite');
      const store = transaction.objectStore(this.storeName);
      const request = store.delete(key);

      request.onsuccess = () => resolve();
      request.onerror = () => reject(request.error);
    });
  }
}

2. 在内容脚本中替换原存储逻辑

用封装的工具类替代chrome.storage.local的调用:

// 初始化存储实例
const storage = new ExtensionStorage();

// 原chrome.storage.local.set替换为以下代码
try {
  await storage.set('arr', []);
  console.log('数据存储成功');
} catch (err) {
  console.error('存储失败:', err);
}

// 获取数据示例
const arr = await storage.get('arr');
console.log('获取到的数据:', arr);

方案优势

  • 兼容性:Safari全平台(含移动端)内容脚本均支持IndexedDB,无配额异常问题;
  • 稳定性:无需依赖Service Worker,规避了Safari中Service Worker被频繁回收的风险;
  • 功能匹配:支持数组、对象等复杂数据类型存储,完全覆盖chrome.storage.local的核心需求;
  • 性能达标:读写性能足以满足扩展常规存储场景的需求。

注意事项

  • 首次使用需确保数据库初始化完成,封装类已通过init方法自动处理;
  • 若存储大量结构化数据,可添加索引优化查询效率;
  • 需捕获并处理存储操作的异常,避免影响内容脚本正常逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 13:42:39