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,
})
工作原理
- SSR 短路:
import.meta.server为true时直接 return,status保持'loading',不发起任何网络请求与解密 - 缓存查询:
fileId = md5(new URL(url).pathname).toUpperCase(),先查 IndexedDB 对应 store 表;命中走fromCache(data)返回业务结果 - 远程加载 + 条件解密:未命中则
fetch(url)拿到ArrayBuffer;url含.bnc走decryptBinary(buf, key),否则跳过解密直接走toCache - 写缓存:
toCache编码后的数据写入 IndexedDB(下次秒开),同时result从null→ 业务结果,status从'loading'→'loaded'。写缓存是可降级旁路——不 await(渲染不等 DB),且写失败被静默忽略(fw#380) - 响应式重载:
reactive: true时用watchEffect监听url响应式变化,自动重新执行流程;false(默认)时仅onMounted触发一次
Options
| 名称 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
url | MaybeRef<string> | ✓ | — | 资源 URL,可传响应式(Ref / computed) |
key | string | ✓ | — | 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)) |
reactive | boolean | false | true 用 watchEffect 监听 url 响应式变化;false 仅 onMounted 触发一次 |
返回值
| 名称 | 类型 | 说明 |
|---|---|---|
status | Ref<'loading' | 'loaded' | 'error'> | 当前加载状态。SSR 阶段始终为 'loading' |
result | Ref<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 或作用域销毁后,旧请求不再回填;已发出的网络请求不会主动取消。