useDecryptedAsset()

useDecryptedAsset 是 SwImage、SwAsyncText 共享的底层 composable,把"远程资源加载 → 条件 AES 解密 → IndexedDB 持久化缓存 → 状态机"这套通用逻辑抽出来。业务层一般不直接调用,但需要自定义加密资源加载场景(自管 store 表、自定义编码格式)时可以直接用。

使用方式

真实 .bnc 解密(status + result)

加载中...

通过 toCache / fromCache 两个钩子让调用方决定缓存格式与业务结果格式:

// 示例 1:加密图片 → Blob URL(SwImage 内部就这么用)
const { status, result: blobUrl } = useDecryptedAsset<Blob, string>({
  url: computed(() => props.src),
  key: imgKey,
  table: 'image',
  toCache: buf => new Blob([buf], { type: detectMime(buf) }),
  fromCache: blob => URL.createObjectURL(blob),
})

// 示例 2:加密文本 → 字符串(响应式监听 url 变化,SwAsyncText 内部用法)
const { result: text } = useDecryptedAsset<Uint8Array, string>({
  url: computed(() => props.url),
  key: imgKey,
  table: 'text',
  toCache: buf => new Uint8Array(buf),
  fromCache: bytes => new TextDecoder().decode(bytes),
  reactive: true,
})

工作原理

  1. SSR 短路:import.meta.server 为 true 时直接 return,status 保持 'loading',不发起任何网络请求与解密
  2. 缓存查询:fileId = md5(new URL(url).pathname).toUpperCase(),先查 IndexedDB 对应 store 表;命中走 fromCache(data) 返回业务结果
  3. 远程加载 + 条件解密:未命中则 fetch(url) 拿到 ArrayBuffer;url 含 .bnc 走 decryptBinary(buf, key),否则跳过解密直接走 toCache
  4. 写缓存:toCache 编码后的数据写入 IndexedDB(下次秒开),同时 result 从 null → 业务结果,status 从 'loading' → 'loaded'。写缓存是可降级旁路——不 await(渲染不等 DB),且写失败被静默忽略(fw#380)
  5. 响应式重载:reactive: true 时用 watchEffect 监听 url 响应式变化,自动重新执行流程;false(默认)时仅 onMounted 触发一次

Options

名称类型必填默认值说明
urlMaybeRef<string>✓—资源 URL,可传响应式(Ref / computed)
keystring✓—AES 解密密钥。仅 .bnc URL 实际使用;非加密路径忽略此值,但仍需传
table'image' | 'text'✓—IndexedDB store 表名。约定两个:'image' 给图片类资源,'text' 给文本类
toCache(buffer: ArrayBuffer) => TCached✓—把解密后的 ArrayBuffer 编码为缓存格式(如 new Blob([buf]) / new Uint8Array(buf))
fromCache(cached: TCached) => TResult✓—把缓存格式解码为业务结果(如 URL.createObjectURL(blob) / new TextDecoder().decode(bytes))
reactivebooleanfalsetrue 用 watchEffect 监听 url 响应式变化;false 仅 onMounted 触发一次

返回值

名称类型说明
statusRef<'loading' | 'loaded' | 'error'>当前加载状态。SSR 阶段始终为 'loading'
resultRef<TResult | null>解码后的业务结果。null 表示加载中(或 SSR),非 null 即就绪

注意事项

  • 仅客户端执行——依赖 IndexedDB / fetch / Web Crypto。SSR 阶段函数直接 return,调用方 status 保持 'loading',请用 result === null 提供骨架占位
  • 加密分流由 url 自动判定:含 .bnc 走解密,否则跳过——调用方无需再判断
  • dbGet/dbPut 的数据结构约定为 { id: string, data: TCached },与现有 SwImage / SwAsyncText 缓存格式兼容
  • 写缓存失败会被静默忽略(fw#380):不影响本次渲染(result 来自内存中的 cacheData),也不会冒泡成 unhandledrejection 去污染 errorHandler 的上报。典型触发面是 WebKit 存储受限环境(爬虫 / Safari 隐私模式 / 受限 WebView)写 Blob 进 IndexedDB。读缓存失败按未命中继续远程加载;网络、解密或格式转换失败仍进入 status='error'
  • 未来扩展 store 表名时需要同步在 framework/src/runtime/utils/db.ts 里登记 schema,否则 IndexedDB 写入会失败
  • 过期请求隔离:每次加载先清空旧结果并进入 loading,只有最新请求可更新结果和状态。切到空 URL 或作用域销毁后,旧请求不再回填;已发出的网络请求不会主动取消。