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

基于Go编写的WebAssembly在浏览器中安全持久化数据的技术咨询

在浏览器JS环境中Go WebAssembly的数据持久化方案

一、基础持久化实现方式

Go WebAssembly(Wasm)无法直接访问浏览器存储,必须通过与JS交互调用浏览器原生存储API:

  • localStorage/sessionStorage:适合存储小量键值对数据(比如用户配置、会话标识),Go可通过syscall/js包调用JS的localStorage对象:
package main

import "syscall/js"

func saveLocal(this js.Value, args []js.Value) interface{} {
    js.Global().Get("localStorage").Call("setItem", args[0].String(), args[1].String())
    return nil
}

func main() {
    c := make(chan struct{})
    js.Global().Set("saveLocal", js.FuncOf(saveLocal))
    <-c
}
  • IndexedDB:支持大容量结构化数据存储(几百MB到GB级),支持事务与索引,同样通过syscall/js调用JS的IndexedDB接口,可封装Go层函数简化操作。

二、用SQLite存储大量数据

完全可以实现,借助适配Wasm的sqlite-wasm库,通过JS绑定让Go Wasm调用SQLite实例:

  1. JS侧初始化SQLite(依赖IndexedDB作为持久化后端):
async function initChatDB() {
    const sqlite3 = await window.sqlite3InitModule();
    // "wc"模式:允许写入+自动创建数据库,数据存储到IndexedDB
    window.chatDB = new sqlite3.oo1.DB('chat_history.db', 'wc');
    window.chatDB.exec('CREATE TABLE IF NOT EXISTS messages (id INTEGER PRIMARY KEY, content TEXT, timestamp INTEGER)');
}
initChatDB();
  1. Go侧调用SQLite执行操作:
package main

import "syscall/js"

func execSQL(this js.Value, args []js.Value) interface{} {
    result := js.Global().Get("chatDB").Call("exec", args[0].String())
    return result.String()
}

func main() {
    c := make(chan struct{})
    js.Global().Set("execSQL", js.FuncOf(execSQL))
    <-c
}

该方案性能足以支撑聊天应用的十万级消息存储,容量受浏览器IndexedDB限制(满足日常使用需求)。

三、聊天应用的安全缓存与授权读取

核心通过加密存储+身份验证实现仅授权用户读取:

  • 数据加密:存储前用AES等算法加密消息内容,密钥从用户授权凭证派生(比如登录后的会话密钥、用户密码通过PBKDF2/Argon2生成的密钥)。Go示例:
package main

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "encoding/base64"
    "io"
    "syscall/js"
)

func encryptMsg(this js.Value, args []js.Value) interface{} {
    plaintext := []byte(args[0].String())
    key := []byte(args[1].String()) // 从用户授权信息获取的密钥

    block, _ := aes.NewCipher(key)
    ciphertext := make([]byte, aes.BlockSize+len(plaintext))
    iv := ciphertext[:aes.BlockSize]
    io.ReadFull(rand.Reader, iv)
    
    stream := cipher.NewCFBEncrypter(block, iv)
    stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
    return base64.StdEncoding.EncodeToString(ciphertext)
}

func main() {
    c := make(chan struct{})
    js.Global().Set("encryptMsg", js.FuncOf(encryptMsg))
    <-c
}
  • 身份验证:读取缓存前先验证用户身份(比如校验本地存储的有效JWT、调用后端接口确认会话合法性),验证通过后再解密数据。
  • 额外安全措施:
    • 不存储明文密钥,密钥可由用户实时输入的密码派生,或从后端获取短期会话密钥
    • 定期清理过期缓存数据
    • 敏感消息采用端到端加密(E2EE),确保即使本地缓存泄露也无法解密

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 01:20:33