新闻详情

新闻详情

首页 / 资讯中心 / 详情

Uppy GoldenRetriever 插件完全指南:从浏览器崩溃中恢复文件与续传上传的实现演进

发布时间:2026/9/30 2:01:08来源:尧图网络
Uppy GoldenRetriever 插件完全指南:从浏览器崩溃中恢复文件与续传上传的实现演进
前端UI组件后端【免费下载链接】uppyThe next open source file uploader for web browsers :dog:项目地址https://gitcode.com/gh_mirrors/up/uppy点击查看免费下载GoldenRetriever 是 Uppy 生态中用于「崩溃恢复」的专用插件它在浏览器端把用户已选中的文件与上传进度持久化到 localStorage、IndexedDB 与 Service Worker 中当页面因崩溃、误关标签页而丢失时Uppy 可以像什么都没发生一样恢复全部文件并继续上传。本文以 packages/uppy/golden-retriever/CHANGELOG.md 的版本演进为主线结合 插件源码 与浏览器测试深入讲解其存储架构、恢复流程、选项配置与各版本的关键修复帮助你理解并正确使用这一能力。一、插件定位Uppy 的「金毛寻回犬」从 README.md 可知该插件的核心承诺是把选中的文件保存在浏览器缓存中——元数据存入 localStorage新版本迁移至 IndexedDB所有文件 Blob 存入 Service Worker小 Blob 额外存入 IndexedDB——一旦浏览器崩溃Uppy 可以恢复一切并继续上传仿佛什么都没发生。其 package.json 中的关键词也直接点明了定位crash recovery、resumable uploads、restore files。典型用法来自 README.md 示例import Uppy from uppy/core import GoldenRetriever from uppy/golden-retriever const uppy new Uppy() uppy.use(GoldenRetriever, { // Options })安装$ npm install uppy/golden-retriever插件类本身继承自uppy/core的BasePlugin见 src/index.ts并通过declare module uppy/core扩展了全局事件映射新增restore:plugin-data-changed事件并将GoldenRetriever注册进PluginTypeRegistry。二、双存储架构元数据与 Blob 分离GoldenRetriever 的核心设计原则是元数据与文件数据分开存储文件元数据文件名、大小、进度、类型等体积小但变化频繁适合放入轻量存储文件本体Blob体积大必须放入能容纳大数据的存储介质。2.1 三种浏览器存储的分工从 src/index.ts 的构造函数可以看到三种存储的实例化逻辑存储介质用途说明MetaDataStore/IndexedDBMetaDataStore保存恢复快照files、currentUploads、pluginData6.0.0 起默认使用 IndexedDB不可用时回退 localStorageServiceWorkerStore保存大文件 Blob仅在serviceWorker: true时启用IndexedDBStore保存小文件 Blob始终启用单文件上限 10 MiB总量上限 300 MiBBlob 层的选择逻辑在 src/index.ts// fallback to localStorage when IndexedDB is unavailable this.#metaDataStore IndexedDBStore.isSupported ? new IndexedDBMetaDataStore(metaDataStoreOpts) : new MetaDataStore(metaDataStoreOpts) if (this.opts.serviceWorker) { this.#serviceWorkerStore new ServiceWorkerStore({ storeName: uppy.getID(), }) } this.#indexedDBStore new IndexedDBStore({ expires: this.opts.expires, ...(this.opts.indexedDB || {}), storeName: uppy.getID(), })注意storeName统一取自uppy.getID()即每个 Uppy 实例拥有独立的命名空间互不干扰。2.2 localStorage 版元数据存储MetaDataStoresrc/MetaDataStore.ts 是传统实现存储键前缀为uppyState:实际键名形如uppyState:storeName见getItemKey保存结构StoredState包含expires过期时间戳与metadata含currentUploads、files、pluginData三部分不保存 BlobFileWithoutData类型用Omit..., data显式剔除文件数据因为「不想把 Blob 存进 localStorage」同时避免序列化preview等奇怪属性默认过期时间 24 小时24 * 60 * 60 * 1000默认节流throttleTime: 500msload()时会先执行expireOldState()扫描所有uppyState:前缀的键并删除已过期的条目写入采用throttleleading trailing测试中可通过Symbol.for(uppy test: throttleTime)设为 0 禁用节流写入失败静默吞掉best-effort「配额不足或存储被禁用绝不能破坏上传」。2.3 IndexedDB 版元数据存储IndexedDBMetaDataStore6.0.0 新增CHANGELOG 6.0.0 的第一条 Minor Change 即「Use IndexedDB as a metadata store and fall back to localStorage when IndexedDB is not available.」这是该版本最核心的变更。为什么要迁移src/IndexedDBMetaDataStore.ts 的注释给出了答案大的 Transloadit assembly 状态会突破 localStorage 约 5MB 的配额issue #6280。IndexedDB 没有这么紧的配额限制。实现上有几个关键细节元数据以JSON 字符串存入 IndexedDBStateRecord.metadata为 string而不是直接存活对象。原因见源码注释IndexedDB 通过结构化克隆算法持久化值遇到函数等不可克隆对象会抛错而 localStorage 的JSON.stringify会静默丢弃直接克隆会导致put抛出、快照冻结在早期状态、恢复出来的文件看起来「还没上传」而被标记为 ghostget()保持同步从内存缓存#cache读取因为它会在每次 state 更新时执行写入同样节流默认 500ms读写失败均 best-effort 返回undefined保证恢复失败不拖垮插件构造函数中this.#db.catch(() {})提前挂接拒绝处理器避免连接失败变成 unhandledrejection。对应地src/IndexedDBStore.ts 中新增了METADATA_STORE_NAME metadata对象仓库数据库版本升至v4并在onupgradeneeded中处理oldVersion 4的建仓逻辑含expires索引。浏览器测试 test/goldenRetriever.browser.test.ts 也验证了这一行为// On the default path the snapshot is persisted to IndexedDB, so the old // localStorage backend must stay untouched (this is the positive mirror of // the localStorage-fallback test). See issue #6280. expect(localStorage.getItem(uppyState:${uppy.getID()})).toBeNull()2.4 IndexedDB Blob 存储IndexedDBStoresrc/IndexedDBStore.ts 负责文件 Blob 的持久化默认参数如下选项默认值含义dbNameuppy-blobsIndexedDB 数据库名storeNamedefault对象仓库内的命名空间GoldenRetriever 传入 Uppy 实例 IDexpires24 小时每条记录的过期时间maxFileSize10 MiB单文件上限超限抛File is too big to store.maxTotalSize300 MiB总容量上限超限抛No space left数据库结构经过多版本演进v2改为单一共享对象仓库fileskeyPath: id并建store索引区分不同 Uppy 实例v3新增expires索引并迁移旧数据补上过期时间v4新增metadata仓库见上文。另外注意两个细节IndexedDBStore.cleanup()是静态方法会删除所有 Uppy 实例中已过期的 Blob 与恢复快照连接无论成功与否都会db.close()释放closeOnVersionChange让连接在别的标签页请求更高版本时自动关闭避免阻塞升级put使用add而非put重复写入会抛ConstraintError——这正是 src/index.ts 中#addBlobToStores捕获该错误并静默放行的原因幂等语义CHANGELOG 5.1.1 中「Dont error when saving indexedDB file that already exists (make it idempotent)」。2.5 Service Worker 存储ServiceWorkerStore ServiceWorker.ts当serviceWorker: true时大文件 Blob 交由 Service Worker 的内存缓存保存。双方通过postMessage通信消息协议定义在 src/ServiceWorker.ts消息类型方向作用uppy/ADD_FILE页面 → SW写入 Blob 到指定 storeuppy/REMOVE_FILE页面 → SW删除指定 fileID 的 Blobuppy/GET_FILES页面 → SW请求全部 Blobuppy/ALL_FILESSW → 页面返回指定 store 的全部 Blobsrc/ServiceWorkerStore.ts 在写入前会waitForServiceWorker()若navigator.serviceWorker.controller已存在则直接 resolve否则监听controllerchange事件。Service Worker 侧src/ServiceWorker.ts通过install时skipWaiting()、activate时clients.claim()保证尽快接管页面并在内存中以FileCacheRecordStoreName, RecordUppyFileId, Blob缓存所有 Blob——这正是「Service Worker 用于大 Blob」的原因SW 进程独立于页面存活页面崩溃后 Blob 仍在。CHANGELOG 5.1.0 中「Converted sw.js to sw.ts so that it can be transpiled, in the build」对应这个文件从 JS 到 TS 的迁移package.json 的sideEffects声明了lib/ServiceWorker.js且 exports 明确暴露./lib/ServiceWorker.js子路径方便你自行注册。三、恢复流程从 install 到 restore-confirmed3.1 安装即恢复#restore插件在install()时立即触发一次#restore()src/index.ts且恢复失败仅记录 warning 不抛错best-effort。#restore()的核心流程加载元数据快照await this.#metaDataStore.load()无快照则直接返回判定整体成功若所有恢复文件的progress.complete !f.error则整个快照被忽略Object.fromEntries(... ? [] : recoveredFiles)。这是 5.1.1 引入的修复 #5927 的逻辑——「如果全部文件都成功上传就别再恢复任何东西只有部分成功时才恢复剩余文件供用户重试」并行拉取 BlobPromise.all([loadFileBlobsFromServiceWorker(), loadFileBlobsFromIndexedDB()])两者任一失败只记 warning组装文件为每个文件标记isRestored: true远程文件file.isRemote数据置为{ size: null }本地文件若尚未上传完成且找不到 Blob则标记为ghostisGhost: true, data: undefined——「幽灵文件」概念正是由此而来且只为未成功上传的文件设置 isGhost5.1.1 的 #5930 修复写回 Uppy statesetState({ recoveredState, currentUploads, files })。只有存在可恢复文件时才设置recoveredState它控制 UI 的「已恢复」提示与currentUploads避免无文件时把已完成的 currentUploads 错误恢复发出事件uppy.emit(restored, recoveredState.pluginData)清理孤儿 Blob删除快照中已不存在对应文件的过期 Blob并记录日志。3.2 用户确认后恢复上传restore-confirmed当 Dashboard 等 UI 展示「恢复」提示、用户点击确认后Uppy 发出restore-confirmed事件触发#handleRestoreConfirmedsrc/index.tsconst { currentUploads } this.uppy.getState() if (Object.keys(currentUploads).length 0) { this.uppy.resumeAll() Object.keys(currentUploads).forEach((uploadId) { this.uppy.restore(uploadId) }) } else { // 没有进行中的上传但恢复了文件直接发起新上传 this.uppy.upload() } this.uppy.setState({ recoveredState: null })3.3 保存时机统一收敛到 state-update5.1.1 之前保存逻辑散落在complete、upload-success、file-removed、file-editor:complete、file-added等多个事件处理器中容易漏掉状态变化。5.1.1 的大重构将其统一收敛到state-update处理器#handleStateUpdatesrc/index.ts从而「不遗漏任何状态更新」并顺带修复了 compressor 插件场景下会存到未压缩原始 Blob 的 bug。#handleStateUpdate的核心逻辑currentUploads变化 →#patchMetadata({ currentUploads })files变化时若上一状态存在未完成文件、而新状态文件为空或全部完成无错误 → 清除recoveredState「全部上传处理成功清理恢复状态」剥掉data与preview字段后保存文件元数据避免把大 Blob 与不可序列化属性写进元数据存储通过对比前后状态计算三类文件新增文件addedFiles、编辑过的文件editedFileBlobsdata发生变化、被删除的文件deletedFiles含「刚完成上传的文件」因为上传成功后 Blob 已无保留价值先删除旧 Blob再写入新 Blob——注意 5.1.1 的修复file-editor:complete此前存在「先删后加未 await」的竞态重构后按顺序await执行。#patchMetadatasrc/index.ts对pluginData采用按键合并而非整体替换因为 pluginData 是按插件 ID 组织键的这是 5.1.1 中restore:plugin-data-changed事件的配套设计替代了原先把函数当事件数据传递的 hack 式restore:get-data因此旧版uppy/transloadit与新版uppy/golden-retriever互不兼容。3.4 清理时机complete 与 upload-success 双重保障5.1.1 修复了多个清理相关的 bug仅在「所有文件都成功」时于complete清理允许用户在部分失败时重试失败文件#5927/#5955新增upload-success处理器单个文件上传成功后立即删除其 Blob避免多文件上传中断时complete尚未触发Blob 泄漏修复 IndexedDB 泄漏此前若 ServiceWorkerStore 存在GoldenRetriever 不会从 IndexedDbStore 删除文件造成存储泄漏4.2.3 修复恢复文件后删除文件再点上传导致的崩溃a0a248a5.2.1 修复没有可恢复文件时不恢复currentUploadsd766c30。四、选项与类型系统4.1 完整选项表GoldenRetrieverOptions定义于 src/index.ts默认值见同文件 L36-L39选项默认值说明expires24 * 60 * 60 * 100024 小时元数据与 Blob 的过期时间过期条目在 load/cleanup 时被清除serviceWorkerfalse是否启用 Service Worker 存储大 Blob开启后需自行注册uppy/golden-retriever/lib/ServiceWorker.jsindexedDB.nameuppy-blobs覆盖 IndexedDB 数据库名indexedDB.version4见 IndexedDBStore.ts数据库版本源码connect()中硬编码idGoldenRetriever插件 ID继承自 BasePluginthrottleTime测试专用500元数据写入节流毫秒数通过Symbol.for(uppy test: throttleTime)注入示例开启 Service Worker 恢复大文件import Uppy from uppy/core import GoldenRetriever from uppy/golden-retriever const uppy new Uppy() uppy.use(GoldenRetriever, { expires: 24 * 60 * 60 * 1000, // 快照保留 24 小时 serviceWorker: true, indexedDB: { name: my-app-uppy-blobs }, })同时记得在页面中注册 Service Workerif (serviceWorker in navigator) { navigator.serviceWorker.register(/uppy-sw.js) }其中uppy-sw.js内容即 src/ServiceWorker.ts 编译后的产物可从uppy/golden-retriever/lib/ServiceWorker.js引入。4.2 类型系统演进5.2.0uppy/core新增PluginTypeRegistry与带类型的getPlugin重载GoldenRetriever 通过declare module uppy/core把自己的具体类型注册进去uppy.getPlugin(GoldenRetriever)无需手传泛型即可获得具体类型5.1.1改进 GoldenRetriever 与 MetaDataStore 的类型修复#restore中filesWithBlobs的隐式any类型4.2.0改用 TypeScript 编译器而非 Babel4.2.0 的 Minor Change4.0.0-beta.1 / 3.2.0迁移到 TS5.1.0补全缺失导出移除 package.json 的main字段以 export maps 作为公共 API 契约。4.3 Export maps 与破坏性变更5.0.05.0.0 为所有包引入 export maps带来两类破坏性变更见 CHANGELOG.mdCSS 导入路径从uppy[package]/dist/styles.min.css改为uppy[package]/css/styles.min.css只能导入根路径显式导出的内容uppy/core/lib/foo.js这类深路径导入不再可用。对于uppy/react、uppy/vue、uppy/svelte依赖 peer dependency 的组件被移到子路径如uppy/react/dashboard避免被迫安装所有 peer 依赖。GoldenRetriever 自身的 exports见 package.json为exports: { .: ./lib/index.js, ./lib/ServiceWorker.js: ./lib/ServiceWorker.js, ./package.json: ./package.json }同时index.ts末尾还导出了MetaDataStoreexport { default as MetaDataStore } from ./MetaDataStore.js便于高级用户复用其存储契约。五、从 3.x 到 6.0版本演进时间线结合 CHANGELOG.md可以梳理出关键演进节点版本关键变化3.0.0切换到 ESM3.0.1修复从 Service Worker 加载文件的条件判断#4115修复 Webcam 无限重渲染#41113.0.2修复 GoldenRetriever 下的重试上传#41553.1.0现代化重构#45203.2.0 / 4.0.0-beta.1迁移到 TypeScript#49894.0.0-beta.5移除未使用的readysetter4.2.3修复「恢复后删文件再点上传」崩溃a0a248a5.0.0Export mapsCSS 路径变更子路径组件导出5.1.0sw.js → sw.ts补全导出移除main字段5.1.1大型内部重构state-update 统一保存、节流位置调整、ghost 语义修正、清理逻辑修复#5927/#5930/#59555.2.0PluginTypeRegistry 与类型化 getPlugin5.2.1无文件时不恢复currentUploadsd766c306.0.0元数据存储从 localStorage 迁移到 IndexedDB不可用时回退 localStorage#6280同时升级共享运行时依赖早期4.1.0 及之前的条目中还包含大量「Included in: Uppy vX」信息说明该插件随 Uppy 主版本同步发布从 4.x 到 6.x包版本号与uppy/core保持对齐见各版本Updated dependencies中的uppy/coreX与uppy/utilsX。六、已知边界与注意事项结合 CHANGELOG 与源码使用时有几个值得注意的行为边界幽灵文件ghost是预期的若某个未完成上传的本地文件在恢复时找不到对应 Blob例如用户删文件后立刻刷新、而节流写入尚未落盘该文件会被标记为isGhost展示给用户这是设计上的兜底而非 bug5.1.1 中明确说明了这一竞态场景Blob 存储有大小上限IndexedDBStore 单文件 10 MiB、总容量 300 MiBmaxFileSize/maxTotalSize可配超出上限的文件请配合 Service Worker 存储或使用uppy/tus等支持断点续传的协议作为替代方案参见 examples/aws-nodejs/routes/sts.js 中「超过 100MiB 用 multipart、GoldenRetriever 通过 ListParts 续传」的配套设计快照默认只保留 24 小时expires过期后localStorage/IndexedDB 中的旧条目会被expireOldState与静态cleanup()清除恢复是尽力而为best-effort元数据读写、Service Worker/IndexedDB 拉取 Blob 的任何失败都只记录 warning 日志绝不阻断上传流程跨包兼容性约束5.1.1 移除restore:get-data内部事件后旧版uppy/transloadit与新版uppy/golden-retriever互不兼容升级时请保持相关插件版本同步启用 Service Worker 需自备注册插件只负责通过postMessage与已注册的 SW 通信ServiceWorkerStore.ts 中的waitForServiceWorker会等待controllerchangeSW 脚本需你自行托管与注册。七、测试与验证插件配备完整的浏览器端集成测试test/goldenRetriever.browser.test.ts使用 Vitest Playwright 驱动真实浏览器通过document.body.innerHTML 模拟页面重载来验证选择文件后刷新页面GoldenRetriever 能恢复文件列表并触发restored事件恢复后点击「Upload 1 file」可正常完成上传且上传成功后再次刷新不会重复恢复已完成的文件uppy.getFiles().length为 0默认路径下快照写入 IndexedDB、localStorage 保持干净uppyState:id为 null。测试通过GoldenRetriever[Symbol.for(uppy test: throttleTime)] 0禁用节流保证断言时机可控。运行测试cd packages/uppy/golden-retriever yarn test八、总结GoldenRetriever 是 Uppy 崩溃恢复能力的基石它以「元数据与 Blob 分离」为架构核心用 localStorage/IndexedDB 保存恢复快照、用 IndexedDB Service Worker 保存文件本体通过state-update统一驱动持久化、以restored/restore-confirmed事件闭环恢复流程。从 3.x 到 6.0 的演进本质上是围绕可靠性统一保存时机、修复竞态与泄漏、幂等写入与容量元数据迁出 5MB 配额限制的 localStorage两条主线持续加固。理解其存储分工、恢复判定与清理策略能让你在生产环境中更安全地启用「浏览器崩溃后一切照旧」的体验。赞分享前端UI组件后端【免费下载链接】uppyThe next open source file uploader for web browsers :dog:项目地址https://gitcode.com/gh_mirrors/up/uppy点击查看免费下载相关推荐Molten错误排查与故障处理10个常见问题解决方案终极指南Molten错误排查与故障处理10个常见问题解决方案终极指南 Molten是一款专为PHP应用设计的 透明链路追踪工具 能够无缝集成Zipkin和OpenTshadcn/ui 无障碍开发实战基于 Radix UI 与 Tailwind 构建符合 WAI-ARIA 和 WCAG 的可访问界面shadcn/ui 无障碍开发实战基于 Radix UI 与 Tailwind 构建符合 WAI ARIA 和 WCAG 的可访问界面 本文是 ui ux pAI 技能前端设计系统突破浏览器限制Uppy大文件分片上传的完整实现方案突破浏览器限制Uppy大文件分片上传的完整实现方案 你是否遇到过用户上传GB级视频时进度条突然卡住是否因网络波动导致几小时的上传前功尽弃本文将详解Uppy前端UI组件后端上一篇Kubernetes服务安全暴露实战Cloudflare Tunnel控制器完整指南下一篇Mongoose OS I2C通信实战传感器数据采集与处理创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Ubuntu 20.04开启root账户全攻略:从sudo密码到SSH远程登录 2026/9/30 2:58:30

Ubuntu 20.04开启root账户全攻略:从sudo密码到SSH远程登录

简介:一份针对Ubuntu 20.04系统的PDF运维操作指南,专门解决默认禁用root账户登录的问题,适合需要直接以root身份进行系统管理或高权限操作的Linux用户。资料以步骤化方式完整梳理了开启root并实现手动登录的全过程,包括利用sudo p…

阅读更多 →
Linux timeout 命令完全指南:指定固定时间并发送固定信号 2026/9/30 2:58:30

Linux timeout 命令完全指南:指定固定时间并发送固定信号

Linux timeout 命令完全指南:指定固定时间并发送固定信号 日常运维中,我们经常需要运行一些可能“卡住”的命令——压测脚本、爬虫、抓包工具、长任务进程。它们平时运行正常,但偶尔会因为网络抖动、死锁、等待输入等原因一直不退出&#xff…

阅读更多 →
Brocade 6510参数表详解:从选型到部署的SAN交换机实践指南 2026/9/30 2:58:30

Brocade 6510参数表详解:从选型到部署的SAN交换机实践指南

简介:Brocade 6510光纤通道交换机参数表以官方数据为基础,整理成一份可直接查阅的速查文档,适合数据中心网络工程师、存储管理员和运维人员用于设备选型、容量规划及配置排障。内容按系统架构、性能指标、Fabric服务、管理安全等维度组织&…

阅读更多 →
CCNA 200-301备考全攻略:知识映射、实验环境与盲配冲刺 2026/9/30 2:58:30

CCNA 200-301备考全攻略:知识映射、实验环境与盲配冲刺

简介:《CCNA 200-301官方认证指南》第二版(英文版)是备考思科CCNA 200-301认证的权威参考书,面向希望系统掌握网络基础与实用技能的网络工程师和技术人员。全书涵盖网络基础知识、TCP/IP协议栈、以太网LAN与广域网WAN、IP路由、VL…

阅读更多 →
0基础面试2 2026/9/30 2:58:30

0基础面试2

01 Q:请描述 TCP 三次握手建立连接、四次挥手断开连接的完整过程。为什么建立连接必须是三次,两次/四次都不行?主动关闭方为什么必须进入 TIME_WAIT?为什么是 2MSL?会带来什么问题,有哪些优化手段&#x…

阅读更多 →
H3C网络设备巡检模板:16项检查命令与自动化脚本指南 2026/9/30 2:58:17

H3C网络设备巡检模板:16项检查命令与自动化脚本指南

简介:面向网络运维人员与H3C设备管理者,这份专业巡检模板适用于路由器、交换机、防火墙等各类H3C网络设备,用于将日常分散的检查命令整合为标准化巡检流程。模板覆盖从设备基本信息、软件版本与运行时间、CPU/内存利用率、模块与电源风扇状态…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉