NullChat 使用说明书(客户端 + 服务器端)
编写日期:2026-10-12 | 适用版本:客户端 0.1.0(Flutter 3.47.1)· 服务端 nullchat-server
编写依据:逐条对照当时的源码(页面文件、router.go、config.go),不写代码里没有的东西。
读法建议:只想用 App ⇒ 读第一部分;要自己搭服务器 ⇒ 读第二部分。
⚠️ 本文与实现可能随时间漂移。发现不符时以代码为准,并按《大更新流程》同步本文。
第一部分 客户端(Android App)
0. 名词与总览
| 名词 | 含义 |
|---|
| 注册 ID | 你的账号名(3–32 位,字母开头,可含字母/数字/下划线)。创建后不可修改 |
| 昵称 | 对方看到的名字(可改;暂不支持头像) |
| 安全码 | 一串用于确认"没有中间人"的号码;必须通过其它渠道与对方核对 |
| 端到端加密 | 消息在你手机上加密后才发出;服务器只有密文 |
| 阅后即焚 | 对方读到后约 5 秒,双方本机与服务端密文都会被清除 |
| 会话 | 一条聊天记录(单聊或群聊) |
界面总览:底部有 4 个标签 —— 消息 / 群聊 / 联系人 / 我。
1. 首次启动
1.1 引导页(Onboarding)
| 按键 | 作用 |
|---|
| 我有服务器地址 | 进入服务器设置页,填写你自己的(或朋友给你的)服务器地址 |
| 先去登录 | 直接去登录页(服务器地址已填过时用) |
引导页展示三条产品承诺:"消息在你手机上加密后才发出去"、"你需要一台自己的服务器"、"没有广告、没有推荐"。
1.2 服务器设置页
| 按键 / 字段 | 作用 | 说明 |
|---|
| 服务器地址 输入框 | 填 主机:端口(例如 chat.example.com:443) | 只填域名/IP + 端口,不要带 https://(界面会校验) |
| 保存 | 保存地址并校验连通性 | 保存失败会给出原因 |
| 查看详情 | 展开诊断信息(含实际使用的三个接口地址,等宽字体) | 排查"连不上"时用 |
| 高级设置 开关 | 打开后可手动指定三个接口地址 | 仅用于非标准端口或自定义路径;普通用户不要动 |
2. 登录 / 注册 / 找回密码
2.1 登录页
| 按键 / 元素 | 作用 |
|---|
| 注册ID 输入框 | 填你的注册 ID |
| 密码 输入框 | 填密码 |
| 眼睛图标(tooltip:显示密码 / 隐藏密码) | 切换密码明文显示 |
| 登录(大按钮) | 登录 |
| 服务器设置(右上角) | 改服务器地址 |
| 注册账号 | 去注册页 |
| 忘记密码 | 去找回密码页 |
底部服务器行(服务器:host:port) | 点它直接去服务器设置;未设置时显示"还没有设置服务器,点这里填写" |
| 去设置服务器(弹窗内) | 未填地址就点登录时的引导按钮 |
2.2 注册页
| 按键 / 字段 | 作用 / 规则 |
|---|
| 注册ID | 3–32 位,字母开头,可含字母/数字/下划线 |
| 密码 | 至少 10 位,需含大小写字母和数字 |
| 眼睛图标 | 显示 / 隐藏密码 |
| 昵称 | 对方看到的名字(暂不支持头像) |
| 邮箱 | 仅用于找回密码(务必填对) |
| 注册 NullChat | 提交注册 |
| 已有账号?去登录 | 返回登录页 |
2.3 找回密码页
| 按键 / 字段 | 作用 |
|---|
| 注册邮箱 | 填注册时用的邮箱 |
| 邮箱验证码 | 收到的验证码(有发送频率限制) |
| 新密码 | 至少 10 位,含大小写字母和数字 |
| 眼睛图标 | 显示 / 隐藏密码 |
| 找回密码 | 提交重置 |
2.4 修改密码页(两种入口)
| 按键 / 字段 | 作用 |
|---|
| 当前密码 / 临时密码(当前密码) | 后者出现在"管理员重置密码后强制改密"的情形 |
| 新密码 / 确认新密码 | 至少 10 位,含大小写字母和数字 |
| 显示密码 | 切换明文显示 |
| 修改密码 | 提交。成功后所有设备都需用新密码重新登录 |
| 先跳过(稍后再改) | 仅在主动改密入口出现;强制改密流程里不给跳过 |
2.5 安全锁页(PIN)
| 按键 / 字段 | 作用 |
|---|
| PIN / 再次输入 PIN | 设置或确认 PIN |
| 指纹快捷解锁 开关 | 允许用指纹/人脸快捷解锁(PIN 仍始终可用,指纹失败时不会把用户锁在外面) |
| 开启 / 关闭安全锁 | 开关安全锁。关闭时需先输入当前 PIN |
| 解锁界面上的 PIN 输入 + 指纹按钮 | 启动 App 时解锁 |
PIN 由加盐哈希保存;连续输错会节流(防暴力破解)。
3. 「消息」标签(会话列表)
| 按键 / 元素 | 作用 |
|---|
| ⊕ 添加联系人(右上角) | 去「添加联系人」页 |
| 点某条会话 | 进入聊天 |
| 长按某条会话 | 弹出「删除会话」确认框(取消 / 删除)。仅删除本地会话记录 |
| 下拉 | 刷新会话列表 |
| 空态按钮「添加联系人」 | 没有会话时的引导按钮 |
3.1 「过期未收提醒」行(重要)
有人给你发消息、而你当时不在线 ⇒ 消息进入服务端 24 小时加密缓存;到期清理后, 服务端只保留一条元数据占位:发送者 | 时间 | N 条消息未收到,已过期删除。 它不含任何正文,也不可打开(灰色、无箭头)。
| 操作 | 效果 |
|---|
| 点一下这一行 | 消除:立刻从列表移除,并同步删除服务端那条记录(换设备/重登也不会再出现) |
| 不点它 | 服务端最多保留 7 天,到期自动清理 |
⚠️ 刻意没有"按时间自动隐藏":那会让你在没看到时就错过这条信息。
4. 聊天页(按键最密集,重点)
4.1 标题栏
| 按键 | 作用 |
|---|
| ← 返回(tooltip:返回) | 回到上一页 |
| 头像 + 名字 / 群名(点标题) | 单聊:进入该好友的资料页(那里有安全码);群聊:进入群资料页 |
| ⋯(tooltip:好友资料与安全码) | 单聊:进好友资料页 |
| ⋯(tooltip:群资料) | 群聊:进群资料页(群里没有"peerID",因此这里不冒充"好友资料") |
4.2 常驻提示条(仅在需要时出现)
对方加密身份变更后,会话顶部会出现一条红色提示条(不随消息滚动消失):
| 按键 | 作用 |
|---|
| 我已核对 | 你已在其它渠道核对过安全码 ⇒ 关闭这条提示(同时把它记为"已读") |
4.3 消息气泡
| 操作 | 效果 |
|---|
| 长按自己的/对方的气泡 | 弹出菜单:复制 / 删除 / 取消 |
| 复制 | 把该条文本复制到剪贴板(提示"已复制") |
| 删除 | 二次确认后只从你手机上删除,对方仍能看到(E2EE 下做不到"撤回") |
| 「已读」标记 | 单聊里,你发出的最后一条消息在对方阅读后显示「已读」(受对方「发送已读回执」开关控制)。退出会话再进来仍会保留(记录在本机;换手机/重装后不再显示,与旧消息读不出来同理) |
| 「已焚毁」 | 阅后即焚消息焚毁后的痕迹(占位提示,不可打开) |
| 加密信息条目 | 会话内的系统类提示(如安全码变更记录) |
4.4 输入栏(一个按钮,两种发送)
| 元素 | 手势 | 作用 |
|---|
| 输入框 | 输入 | 多行文本(1–4 行自动增高);键盘回车键=发送 |
| 发送(默认外观) | 点击 | 发送普通消息 |
| 发送 | 长按 | 切换为阅后即焚模式(切换时会有一条提示;发送成功不再提示) |
| 焚毁(红色 + 🔥 图标) | 点击 | 发送阅后即焚消息:对方读到后约 5 秒自动焚毁 |
| 焚毁 | 长按 | 切回普通发送 |
模式是可见的:一旦进入焚毁模式,按钮立刻变成红色并显示 🔥「焚毁」——
你不看提示也能知道"现在按下去会发什么",避免误发。
阅后即焚的边界(务必知道):焚毁从"对方读到"开始计时;
对方若是截图、或在你发消息时离线(消息进服务端缓存),行为按上面的规则处理;
焚毁会清理本机明文缓存 + 对端明文缓存 + 服务端密文缓存三处。
5. 「群聊」标签
| 按键 | 作用 |
|---|
| ⊕ 创建群聊(右上角) | 去创建群聊页 |
| 点某个群 | 进入群聊 |
| 空态按钮「创建群聊」 | 没有群时的引导按钮 |
5.1 创建群聊页
| 按键 / 字段 | 作用 |
|---|
| 群名称 | 填群名(界面提醒:不要把私密信息写进群名) |
| 选择成员 | 从好友里勾选成员 |
| 创建群聊 | 创建(无好友时提示"还没有好友,先添加好友才能建群") |
5.2 群资料页
| 按键 | 作用 |
|---|
| 群成员 列表 | 查看成员(显示人数) |
| 邀请成员 | 从好友里勾选并邀请(无可邀请好友时给出空态) |
| 解散群聊(群主) | 二次确认后解散(解散) |
| 退出群聊(非群主) | 二次确认后退出(退出群聊) |
| 取消(确认框) | 什么都不做 |
群聊的加密方式:逐成员扇出(给每个成员单独加密一份),不是组密钥。
6. 「联系人」标签
| 按键 | 作用 |
|---|
| ⊕ 添加联系人(右上角) | 去「添加联系人」页 |
| 新的朋友(带数字角标) | 查看好友申请(角标=待处理数量) |
| 点某个好友 | 进入好友资料页 |
| 长按某个好友 | 弹出「删除好友」确认框(取消 / 删除):删除后需重新添加才能聊天 |
| 空态 | 提示去「添加联系人」用注册 ID 搜索 |
6.1 添加联系人页
| 按键 / 字段 | 作用 |
|---|
| 输入对方注册ID | 填对方 ID(顶部也会显示你自己的 ID,方便对方加你) |
| 搜索 | 搜索该 ID |
| 添加好友 | 发起好友申请 |
| 验证消息 | 申请附言(界面明确提醒:验证消息不加密,勿填敏感信息) |
| 发送 | 发送申请 |
| 取消 | 关闭填写框 |
6.2 新的朋友页
| 按键 | 作用 |
|---|
| 同意 | 通过申请(成为好友) |
| 拒绝 | 拒绝申请 |
| 空态 | "暂无新的好友申请",并提示可去「添加联系人」搜索 |
6.3 好友资料页
| 按键 / 元素 | 作用 |
|---|
| ID: xxx | 对方注册 ID(不可改) |
| 备注名 | 改备注(仅自己可见,但服务器可见——界面已注明) |
| 安全码 | 进入安全码核对页("核对后可以确认没有人在中间偷看你们的消息") |
| 发消息 | 直接进入与该好友的聊天 |
| 删除好友 | 二次确认后删除(取消 / 删除) |
7. 「我」标签
页面自上而下:ID + 复制按钮,然后6 个入口。
| # | 入口 | 作用 |
|---|
| — | ⧉ 复制按钮(ID 右边) | 复制你的注册 ID 到剪贴板(提示"已复制注册ID") |
| 1 | 个人资料 | 查看注册 ID / 昵称 / 邮箱绑定状态 / 注册时间 / 最后登录;每行右侧有复制按钮 |
| 2 | 修改密码 | 自助改密(见 §2.4) |
| 3 | 端到端加密 | 加密说明页(做到了什么 / 做不到什么) |
| 4 | 设备管理 | 查看登录过本账号的设备并踢出 |
| 5 | 设置 | 见 §8 |
| 6 | 退出登录(红色) | 退出并回到登录页(见 §10.3) |
7.1 设备管理页
| 按键 / 元素 | 作用 |
|---|
| 本机设备(本机) 行 | 当前这台设备 |
| 其它设备行 | 同一账号登录过的其它设备 |
| 退出本机登录(tooltip,本机那行的图标) | 本机退出登录 |
| 踢出「设备名」(tooltip,其它设备行的图标) | 二次确认后把该设备踢下线 |
| 取消 / 踢出(确认框) | 确认或取消 |
| 空态 | "没有其它设备"(只显示本机时) |
每台设备有一个本机稳定 ID:同一台机器永远复用同一个 ID,因此正常使用不会产生重复设备行;
只有卸载/清除数据后重新登录,才会被记为一台"新设备"。
7.2 安全码页
| 按键 / 元素 | 作用 |
|---|
| 你的安全码 + 一串号码 | 等宽显示,供核对 |
| 复制 | 复制安全码 |
| 刷新 | 重新获取/计算 |
| 数字一样,标记为已验证 | 你已在其它渠道核对一致 ⇒ 标记为已验证 |
| 取消已验证标记 | 撤销上面的标记 |
| 重试 | 加载失败时重试 |
⚠️ 核对必须走其它渠道(当面、电话、另一款工具)。不要把安全码发到本 App 的聊天里核对——
那等于用"可能已被劫持的通道"去验证这个通道本身。
7.3 高安全模式说明页
纯说明页(无操作按钮),六节:它防的是什么 / 两种模式的行为差别 / 为什么默认是「关」/ 怎么核对安全码 / 那我该开还是关 / 两个常见疑问。
8. 设置页(逐项)
| 项 | 类型 | 作用 |
|---|
| 服务器设置 | 入口 | 改服务器地址(同 §1.2) |
| 通知内容预览 | 开关(默认关) | 打开后通知栏/锁屏会显示消息内容;关闭时只显示"您有 N 条新消息"。关闭状态绝不包含正文 |
| 安全锁 | 开关 | 启动 App 需输入 PIN(见 §2.5) |
| 高安全模式 | 开关(默认关) | 见下 |
| 高安全模式说明 | 入口 | 进说明页(见 §7.3) |
| 后台保活 | 开关(默认关) | 开启后前台服务保持连接以即时收消息;代价是一条常驻通知(系统强制,无法隐藏) |
| 打开电池优化设置 | 入口(仅保活开启且未加白名单时出现) | 跳到系统电池优化页,把 NullChat 加入白名单 |
| 发送已读回执 | 开关(默认开) | 关掉后对方看不到你的已读状态(注意:已读记录仍由服务器产生,只是不显示给对方) |
8.1 「高安全模式」到底做什么
| 模式 | 遇到"对方加密身份变了"时的行为 |
|---|
| 关(默认) | 自动接受新身份(消息立刻恢复),并在会话里留一条显眼的红色提示条;你可以在提示条上点「我已核对」 |
| 开 | 不自动接受,弹对话框要你亲自确认;对话框给出对方当前安全码,并有三个动作:接受 / 取消 / 「对方重装过 → 接受并重建」 |
为什么默认是"关":接受新身份是人的决定,程序不能替你点。默认开着会导致 "对方换手机后你这边永久读不出消息"(实测过,且重启也好不了)。 默认关 = 先让消息通、再显眼提示(与主流做法一致);代价是"自动信任"。
高安全模式的代价:对方每次换机/重装,你都要手动点一次;不点就一直显示「无法解密」。
9. 通知与后台
| 主题 | 说明 |
|---|
| 通知内容 | 默认不预览(见设置页「通知内容预览」)。锁屏/通知栏只显示"您有 N 条新消息" |
| 后台保活 | 默认关。开启后有一条常驻通知;建议同时加入电池优化白名单(设置页有直达入口) |
| 阅后即焚的预览 | 会话列表对该类消息一律显示 [阅后即焚],不会泄露正文 |
10. 隐私与安全操作
10.1 核对安全码(防中间人)
- 聊天页 → ⋯ → 好友资料页 → 安全码(或直接进入安全码页);
- 两人各自看到一串号码,通过其它渠道(当面/电话/另一款工具)逐位核对;
- 完全一致 ⇒ 点「数字一样,标记为已验证」;
- 不一致 ⇒ 有人在中间,不要继续在该会话里发送敏感内容。
10.2 阅后即焚怎么用
长按发送按钮 ⇒ 按钮变红显示 🔥焚毁 ⇒ 再点击即发送。 对方读到后约 5 秒焚毁;焚毁后双方都只剩「已焚毁」痕迹。
10.3 「退出登录」会清掉什么
退出登录(「我」→ 退出登录)会:断开连接、取消通知、清除本机 E2EE 身份与会话材料、 清除明文缓存、清除登录 token。后果:
- 本机旧消息读不出来(密钥只存在本机,这是加密的必然代价);
- 本机被记为一台"新设备"(设备列表会多一行);
- 需要重新输入账号密码登录。
10.4 换手机 / 重装后会发生什么
| 场景 | 结果 |
|---|
| 你换了手机 | 新手机上旧消息读不出来(必然代价);对方会看到"你的安全码已变更"并(默认)自动恢复通信;此后新消息正常 |
| 对端换了手机 | 你这边默认会自动接受新身份并留下红色提示条;建议点「我已核对」并核对安全码 |
| 双方都重装 | 互发一条消息即可恢复(默认模式下无需人工点击) |
第二部分 服务器端
11. 组成与端口(线上实测)
| 组件 | 容器(实测名) | 作用 |
|---|
| 自研服务 | nullchat-server | 注册/登录/改密/设备/提醒/E2EE 预密钥/焚毁清理;对外只监听本机端口,由 nginx 反代 |
| 数据库 | nullchat-mongodb | 账号、设备、占位提醒、审计;不含消息正文 |
| 缓存 | nullchat-redis | OpenIM token、离线密文缓存、消息缓存(AOF 已开启) |
| 反向代理 | nullchat-nginx | TLS 终止 + 反代(对外 https://域名:443) |
| OpenIM | openim-*(server/api/msggateway/msgtransfer/rpc-*/push 等 + nullchat-etcd) | 消息收发管道 |
deploy/nullchat-compose.yml 是片段(只含自研服务);线上实际编排以服务器 /opt/nullchat/deploy/ 为准。
12. 首次部署(要点)
- 准备:一台 Linux 服务器 + 域名 + 证书;Docker 与 compose。
- 取源码:把
server/ 上传到服务器(例如 /opt/nullchat/nullchat-src)。
🔴 务必先校验目录:head -1 go.mod 必须是 module nullchat/server,否则说明传错地方了。
- 写
.env(与 compose 同目录):至少设置
NULLCHAT_JWT_SECRET、NULLCHAT_ADMIN_TOKEN(两个都不能用默认值 change-me-in-prod)、 NULLCHAT_MONGO_URI、NULLCHAT_REDIS_ADDR/PASS、NULLCHAT_OPENIM_*、SMTP 相关(要用找回密码就必须配)。
- 建镜像:
docker build -t nullchat-server:<标签> /opt/nullchat/nullchat-src。
⚠️ compose 里是 image: + read_only: true(没有 build:)⇒ 改代码必须重建镜像再 docker compose up -d --force-recreate nullchat-server;容器内直接换二进制不行(rootfs 只读)。
- 起服务:先 Mongo/Redis/etcd/OpenIM,最后自研服务与 nginx。
- 自检:
GET /healthz 应为 200;随便打一个受保护接口应为 401(而不是 404/500)。
13. 日常运维
| 目的 | 命令(示例) |
|---|
| 看容器状态 | sudo docker ps --format '{{.Names}}\t{{.Status}}\t{{.Image}}' |
| 看自研服务日志 | sudo docker logs --tail 200 nullchat-server |
| 健康检查 | curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:<端口>/healthz |
| 进 Mongo | sudo docker exec -it nullchat-mongodb mongosh "mongodb://<用户>:<口令>@127.0.0.1:27017/?authSource=admin" |
| 进 Redis | sudo docker exec -e REDISCLI_AUTH="$PASS" nullchat-redis redis-cli |
| 重启自研服务 | sudo docker compose -f <compose> up -d --force-recreate nullchat-server |
🔴 两条纪律:
- Mongo 必须显式选库:
db.getSiblingDB('nullchat') —— URI 不带库名时 mongosh 会落在 test 库(会查出与服务端不符的"0 行")。 - 不要把口令放进命令行:用环境变量(如
REDISCLI_AUTH)传入,且不要用 2>/dev/null 藏错误。
14. 配置项(internal/config/config.go,节选)
| 环境变量 | 默认 | 说明 |
|---|
NULLCHAT_HTTP_ADDR | :8080 | 监听地址(线上由 compose 覆盖) |
NULLCHAT_MONGO_URI / _DB | mongodb://127.0.0.1:27017 / nullchat | 数据库 |
NULLCHAT_REDIS_ADDR / _PASS / _DB | 127.0.0.1:6379 / 空 / 0 | 缓存 |
NULLCHAT_JWT_SECRET | change-me-in-prod | 🔴 必须改 |
NULLCHAT_ADMIN_TOKEN | change-me-in-prod | 🔴 必须改(管理接口口令) |
NULLCHAT_ACCESS_TTL_HOURS / _REFRESH_TTL_HOURS | 168 / 720 | token 有效期 |
NULLCHAT_EMAIL_AES_KEY | 空 | 邮箱字段加密密钥 |
NULLCHAT_SMTP_HOST/PORT/USER/PASSWORD/FROM | 空 / 465 / 空 / 空 / NullChat 系统 | 找回密码邮件;不配则找回功能不可用 |
NULLCHAT_OPENIM_BASE_URL / _SECRET / _ADMIN_ID | http://127.0.0.1:10002 / 上游默认 / imAdmin | OpenIM 对接 |
NULLCHAT_REGISTER_LIMIT_PER_IP | 50 | 注册限速 |
NULLCHAT_LOGIN_MAX_FAILS / _LOCK_MINUTES | 5 / 15 | 登录失败锁定 |
NULLCHAT_SEND_CODE_LIMIT_SECONDS | 60 | 验证码发送间隔 |
NULLCHAT_RESET_VERIFY_MAX_TRY / _SEND_LIMIT_PER_IP_HOURLY / _ATTEMPT_LIMIT_PER_IP_HOURLY | 5 / 10 / 30 | 找回密码限速 |
NULLCHAT_OFFLINE_CACHE_TTL_HOURS | 24 | 离线密文缓存 TTL |
NULLCHAT_PLACEHOLDER_TTL_DAYS | 7 | 过期未收提醒的保留天数(2026-10-12 由 30 缩短) |
NULLCHAT_PURGE_INTERVAL_MINUTES | 1 | 焚毁/清理扫描间隔 |
15. 自研服务端接口一览(internal/api/router.go 原文)
| 方法 | 路径 | 鉴权 | 作用 |
|---|
| POST | /api/v1/auth/register | 无 | 注册 |
| POST | /api/v1/auth/login | 无 | 登录 |
| POST | /api/v1/auth/send_reset_code | 无 | 发送找回验证码 |
| POST | /api/v1/auth/reset_password | 无 | 用验证码重置密码 |
| GET | /api/v1/user/devices | 用户 token | 设备列表 |
| POST | /api/v1/user/devices/kick | 用户 token | 踢出设备 |
| GET | /api/v1/user/notices | 用户 token | 过期未收提醒列表 |
| DELETE | /api/v1/user/notices/:convID | 用户 token | 消除一条提醒(2026-10-12 新增,按 owner_id+conv_id 删除) |
| POST | /api/v1/user/im_token | 用户 token | 重新签发 OpenIM token(自助恢复) |
| POST | /api/v1/user/password | 用户 token | 修改密码 |
| GET | /api/v1/user/password/status | 用户 token | 是否需要强制改密 |
| POST | /api/v1/user/password/verify | 用户 token | 校验当前密码 |
| GET | /api/v1/user/profile | 用户 token | 个人资料 |
| POST | /api/v1/e2ee/prekeys | 用户 token | 上传预密钥包 |
| POST | /api/v1/e2ee/prekeys/consume | 用户 token | 消费(取用)对方预密钥 |
| GET | /api/v1/e2ee/prekeys/:userID | 用户 token | 查询对方预密钥 |
| POST | /api/v1/e2ee/burn | 用户 token | 立即删除服务端密文缓存(阅后即焚用;{peerID 或 groupID, seq}) |
| POST | /api/v1/admin/user/ban / unban | 管理 token | 封禁 / 解封 |
| POST | /api/v1/admin/user/reset_password | 管理 token | 管理员重置密码 |
| GET | /api/v1/admin/audit | 管理 token | 审计查询 |
| GET | /healthz | 无 | 健康检查 |
16. 备份与恢复
| 对象 | 做法 |
|---|
| MongoDB | mongodump(含 nullchat.users/devices/expired_notices/admin_audit_logs 等) |
| Redis | 已开 AOF(重启后 token 与离线密文缓存可存活) |
| 服务端源码/镜像 | 部署前 tar 备份源码 + 备份旧镜像标签(每次都留,回滚一条命令) |
| 恢复顺序 | Mongo → Redis → OpenIM → 自研服务 → nginx |
17. 故障排查
| 现象 | 先查什么 | 常见根因 |
|---|
| 消息发出去对方收不到 | OpenIM 的 msgtransfer/msggateway/rpc-msg/push 是否都在跑;MQ lag/pending | 管道卡住(重启相关容器) |
| 一直"无法解密" | 是否单侧重装过;日志有无 UntrustedIdentity | 身份变更未被接受(默认模式会自动接受;高安全模式需手动确认) |
| 设备列表出现重复 | nullchat.devices 里同 user_id 有多少行 | 旧客户端用 deviceID: null(现已修);历史行可清理(保留 last_login_at 最新一条) |
| 提醒一直不消失 | expired_notices 是否有该 owner_id+conv_id | 客户端未点击(点一下即消除);或保留期未到(最长 7 天) |
| 登录页反复出现 | token 是否过期;POST /user/im_token 是否可用 | token 失效(限时/被踢);可用自助换 token |
18. 安全运维红线
- 消息正文永不落库:
openim_v3.msg = 0;离线只缓存密文(24h)。 - 日志不打正文(含依赖层拦截器);新增日志只允许"计数/ID/状态"。
- 通知默认不预览。
- 凭据不进 git:
调试服务器信息*.txt 已被 .gitignore;提交前必须按《大更新流程》§3.1 做凭据扫描
(含日期快照——版本快照/ 是 git 跟踪目录)。
- 用户触发的删除必须校验归属(如提醒消除走
owner_id + conv_id)。
19. 简明速查(打印版)
【最简单的用法】
1. 装 App → 引导页点「我有服务器地址」→ 填 host:port → 保存
2. 没有账号:登录页「注册账号」→ 填 ID/密码/昵称/邮箱 → 注册
3. 加好友:消息页右上角 ⊕ → 填对方注册 ID → 搜索 → 添加好友(附验证消息)
对方在「联系人 → 新的朋友」点「同意」
4. 聊天:消息页点会话 → 输入 → 点「发送」
5. 阅后即焚:长按「发送」→ 按钮变红🔥「焚毁」→ 再点发送(对方读到后约 5 秒焚毁)
6. 复制某条消息:长按气泡 → 复制
7. 防止中间人:⋯ → 好友资料 → 安全码 → 用别的渠道核对 → 标记已验证
8. 改服务器:登录页右上「服务器设置」或 我 → 设置 → 服务器设置