useLocal / useSession
帶 AES 加密的瀏覽器儲存響應式封裝:useLocal(localStorage,跨工作階段持久)與 useSession(sessionStorage,關分頁即清),以及對應的全量清空函式 clearLocal / clearSession。4 個匯出全部 auto-import。
📌 前端快取一律走這兩個 util,禁止裸用
localStorage/sessionStorage/document.cookie(CACHE-001,blocker)。裸用漏三件事:漏cachePrefix(多專案共用網域時 key 互撞串資料)、明文儲存(無 AES)、模組頂層存取在 SSR 期 500。例外僅限第三方 SDK 自管的 storage。
運作原理
- 在 VueUse
useLocalStorage/useSessionStorage之上注入自訂 serializer:讀寫時透明呼叫 aes 的decryptData/encryptData,金鑰取runtimeConfig.public.cacheAesKey。 - 鍵名自動拼接
runtimeConfig.public.cachePrefix,多專案共用網域時互不干擾。 - SSR 環境下降級為
initialValue,不存取window—— 伺服器端也能安全呼叫。 clearLocal/clearSession在伺服器端為 no-op。
設定在 nuxt.config.ts 的 runtimeConfig.public(專案常數直接寫實值,隨程式碼走;執行期同名 NUXT_PUBLIC_* 程序環境變數仍可臨時覆蓋):
cachePrefix: 'c_' // 快取 key 前綴
cacheAesKey: 'your-16-byte-key' // AES 金鑰(16 / 24 / 32 位元組)
⚠️
cacheAesKey在runtimeConfig.public.*,會進用戶端 bundle —— 加密僅作 obfuscation,不是安全屏障。詳見用戶端加密的安全邊界。
⚠️
cacheAesKey必須是 16 / 24 / 32 位元組(按 utf8 位元組數計)。非法長度時 CryptoJS 加密能產出密文、解密回空 —— 寫入成功、讀取永遠失敗、且無任何報錯(靜默資料遺失)。framework 在建置期與 dev 執行期都會檢出並告警。
API
| 函式 | 簽名 | 說明 |
|---|---|---|
useLocal | <T>(key: string, initialValue: T) => RemovableRef | localStorage 響應式 Ref,直接賦值寫入,.remove() 刪除該 key |
clearLocal | () => void | 清空整個 localStorage(含非本專案 key,慎用);伺服器端 no-op |
useSession | <T>(key: string, initialValue: T) => RemovableRef | sessionStorage 響應式 Ref,分頁關閉自動清除 |
clearSession | () => void | 清空整個 sessionStorage;伺服器端 no-op |
使用範例
useLocal 寫讀 + localStorage 密文對照
// 使用者偏好(長期保留 → useLocal)
const prefs = useLocal('ui-prefs', { theme: 'auto', lang: 'zh-CN' })
prefs.value.theme = 'dark' // 加密寫入
// 多步表單草稿(關分頁即清 → useSession)
const draft = useSession('post-draft', '')
draft.value = '暫存的正文…'
draft.remove() // 刪除該 key
// typed nullable:賦 null 即刪除
const account = useLocal<AccountInfo | null>('account', null)
account.value = null
// 登出時全量清理
function logout() {
clearLocal()
clearSession()
}
生命週期選型(CACHE-002,warning)
| 這份資料… | 用 |
|---|---|
| 要跨工作階段保留 / 跨分頁共享(偏好、草稿匣、記住我) | useLocal |
| 一次性 / 單分頁中轉(多步表單草稿、列表→詳情標誌) | useSession |
典型翻車:長期偏好用了 useSession(關分頁資料沒了);想跨分頁同步的狀態用了 useSession(另一個分頁讀不到)。
注意事項
clearLocal()/clearSession()是全清、不按 cachePrefix 過濾(CACHE-003):內部就是裸localStorage.clear()—— 多專案共用網域時會把其它專案的資料一起清掉。獨佔網域(絕大多數 applier)的登出全清可接受;共用網域 / 只清本模組時改用各 Ref 的.remove()精確刪。- hydration mismatch:伺服器端首次渲染回傳
initialValue,水合後切換到用戶端實際值;若初值與實際不同且直接渲染進模板,可能觸發 hydration 警告,可搭配<ClientOnly>規避。 - 敏感欄位(密碼 / 私鑰)禁止放 cookie(隨每個請求上線路 + DevTools 可見),應放
useLocal(僅主動 JS 讀取時使用)。
useCookie(加密 cookie)
framework 以同名 auto-import 覆蓋了 Nuxt 內建 useCookie(framework#199)——applier 裸寫 useCookie(key, opts) 拿到的即 framework 加密版:鍵名自動拼 cachePrefix、值經 AES 透明加解密(與 useLocal / useSession 同一安全模型:obfuscation 非安全屏障),回傳 WritableComputedRef<T | null>,賦 null 即刪除。支援透傳 maxAge / sameSite / secure / path / domain / default。
const token = useCookie<string>('token', { maxAge: 60 * 60 * 24 * 30, sameSite: 'lax', secure: true })
token.value = 'abc' // 自動加密寫入
token.value = null // 刪除 cookie
需要 Nuxt 原生明文版時顯式
import { useCookie } from 'nuxt/app'(極少數場景,如讀第三方寫入的明文 cookie)。