鸿蒙端云一体:用 Appwrite 自托管后端做一个单词打卡 App

举报
yd_288537773 发表于 2026/11/09 09:45:19 2026/11/09
【摘要】 用 ArkTS + 自托管 Appwrite 做单词打卡 App:六个云函数收口业务、公开项目ID与密钥边界分离、scrypt 加盐哈希、连续打卡云端聚合,附自托管部署排障。

鸿蒙端云一体:用 Appwrite 自托管后端,做一个单词打卡 App

背单词 App 满地都是,但真正自己从零搭一个「端侧 + 自托管 Serverless 后端」的完整链路,能学到的远比想象多。这篇用 HarmonyOS 的 ArkTS + 自托管 Appwrite,做一个卡片式单词打卡应用:注册登录、闪卡学习、看词选义测试、连续打卡,云侧六个云函数把数据全部收口。

和常见的 FunctionGraph + APIG 方案不同,Appwrite 用「内建 HTTP 路由 + 文档型 NoSQL」把网关层省掉了——端侧只认一个公开的项目 ID,业务校验全在云函数里。

一、为什么选自托管 Appwrite

FunctionGraph 方案要自己配 API 网关、写路由映射、管理函数权限,链路长、排查难。Appwrite 把这几件事内置了:

  • 自带 HTTP 路由和执行入口
  • 自带文档数据库(集合 + 文档),不用另外开 RDS
  • 云函数里用 Server SDK 拿 API Key 读写数据库,端侧完全碰不到密钥

代价是要自己部署和运维。但对个人项目和教学场景,一台 ECS 跑 docker-compose 就够了。

二、数据模型:三个集合

users_col           # 用户:email / password_hash / nickname
words_col           # 58 词词库:word / meaning / level
learn_records_col   # 学习记录:user_id / word_id / status / date

连续打卡的本质是「按 user_id + date 聚合 learn_records」:某天有记录就算打卡,连续天数从今天往前数不间断的日期。把聚合放在云函数里算,端侧只渲染结果,口径只有一处。

三、六个云函数的职责划分

函数 职责
register 邮箱查重 + scrypt 加盐哈希落库
login 常量时间比对密码,签发会话
list-words 按用户进度返回今日 10 个未学词
submit-answer 校验答案,答对写入 learn_records
get-streak 云端聚合连续打卡天数与进度
reset-progress 清空指定用户的学习记录

每个函数都是 ESM 默认导出、node-appwrite v11、execute 设为 any(端侧用公开 ID 直接调)。

四、云函数里怎么安全处理密码

不存明文是最低要求。用 Node 内置 crypto 的 scrypt:

import { randomBytes, scryptSync, timingSafeEqual } from 'node:crypto';

function hashPassword(pw) {
  const salt = randomBytes(16).toString('hex');
  const hash = scryptSync(pw, salt, 64).toString('hex');
  return 'scrypt$' + salt + '$' + hash;
}

function verifyPassword(pw, stored) {
  const parts = stored.split('$');
  const salt = parts[1];
  const hash = parts[2];
  const calc = scryptSync(pw, salt, 64).toString('hex');
  return timingSafeEqual(Buffer.from(calc, 'hex'), Buffer.from(hash, 'hex'));
}

登录用 timingSafeEqual 做常量时间比对,避免响应耗时侧信道泄露信息。

五、端侧网络层只留一个 HttpUtil

端侧所有请求都收敛到一个 HttpUtil,只带公开的项目 ID:

async function callFunction(name: string, payload: object): Promise<any> {
  const res = await http.createHttp().request(
    ENDPOINT + '/v1/functions/' + name + '/executions',
    {
      method: http.RequestMethod.POST,
      header: { 'Content-Type': 'application/json', 'X-Appwrite-Project': PROJECT_ID },
      extraData: JSON.stringify({ body: JSON.stringify(payload) })
    }
  );
  return JSON.parse(res.result as string);
}

项目 ID 是公开的,密钥只存在云函数环境的 API Key 里,端侧永远拿不到——这是自托管方案比「端侧直连数据库」安全的关键。

六、闪卡与看词选义的交互实现

闪卡用 ArkUI 的 rotate 属性做 3D 翻转,点击卡片切换正反面;看词选义是 4 选 1,答对调用 submit-answer 写入记录并更新进度条,答错给一次高亮提示。进度条和外层状态用 State 驱动,学习状态一变界面即时响应。

关键点:逻辑与 UI 解耦。冲突校验、连续打卡计算都是纯 TypeScript 函数,能单独测;UI 只负责把状态画出来。

七、自托管部署里的排障经验

  1. tar.gz 打包上传:Appwrite 部署云函数支持上传压缩包,运行时选 node-16.0。
  2. API Key 权限:云函数要读写数据库,得给 API Key 配对应集合的读写权限,否则 401。
  3. execute 权限:设为 any 让端侧用公开 ID 能直接调;要接入正式鉴权就改成 users,配合端侧会话。
  4. 401 排查:先看 API Key 是否属于该项目、权限是否含目标集合,再看函数运行时版本对不对。

八、这个案例能学到什么

  • 端云一体化里「密钥边界」怎么划:公开 ID 给端侧,敏感密钥锁在云端
  • 文档型 NoSQL 的数据建模:集合 + 文档,比关系型更贴合这类简单业务
  • 连续打卡、进度聚合这类统计,放在云端算一次,比端侧各算各的可靠
  • 自托管 Serverless 的部署与排障,能复用到其他 Appwrite 后端场景

小结

这个案例真正的价值不在记单词本身,而在于跑通「端侧 → 自托管后端 → 云函数 → NoSQL」这条完整链路,并且把安全边界想清楚。对想掌握端云一体化的鸿蒙开发者来说,是个小而完整的练手项目。

案例仓库和云端实践环境在鸿蒙开发实践中心都能找到,配套的建集合、配 API Key、部署函数步骤都在案例文档里。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。