客户端接入指南 按版本号自动挑升级包 · 修复按钮 · 可直接复制
← 返回控制台

客户端接入指南

客户端只要在启动时把自己的版本号报给服务端,服务端就会算出最省流量的升级方式 —— 该给增量包就给增量包,该给完整包就给完整包,跨几个版本都能一步升到最新版。 再加一个「修复」按钮,装坏了也能一键回到官方最新状态。

免登录调用 短地址 / 短参数 sha256 校验 自动挑包 修复兜底

① 一分钟接入

三步,最短只需要记住一条地址。

第 1 步 · 拿到你的应用短码

在控制台选中应用,页面顶部和应用卡片上都能看到短码。下面这条地址里的 app1 就是它:

更新检查地址

第 2 步 · 启动时问一句「我要不要升级」

把 {当前版本} 换成客户端自己的版本号(写 3.0、3.01、3.1.1 都认, 服务端会归一化)。响应里的 recommended 就是服务端替你挑好的那个包, 直接下载它就行 —— 不用自己判断该用增量包还是完整包。

带版本号的实调

第 3 步 · 下载 → 校验 → 覆盖 → 删 removed → 记版本号

解压升级包,把 files/ 里的文件按原相对路径覆盖到安装目录, 按 update.json 的 removed 删掉多余文件, 最后把版本号记成响应里的 latest。完整代码见 第 ⑥ 节。

就这三步。升级包是不是增量、跨了几个版本、要不要改走完整包,全部由服务端判断, 客户端永远只做同一件事:下载 recommended.url → 按同一套规则覆盖。

② 接口一览

带 公开 的都不需要登录,客户端直接调。

作用地址说明
检查更新 公开 /u/{code}?c={版本} 最常用的一个。带上当前版本号,返回是否有新版、推荐哪个包、包的直链与校验值。
修复 公开 /r/{code} 「修复」按钮用。不管当前是什么版本,直接返回最新完整包的直链。
最新清单 公开 /m/{code} 最新版全量文件清单(路径 + sha256 + 大小)。用于本地体检、只补缺失文件、升级后终检。
下载包 /d/{code}/{文件名} 升级包直链。一般不用自己拼,响应里已经给了完整 url。
兼容写法 /api/latest?app=&current=
/api/repair?app=
/api/manifest?app=
与上面的短地址完全等价。app 支持短码、应用目录名、应用中文名三种写法(老地址永久可用)。
版本号进路径 /u/{code}/{版本} 连 query 都省了,例:/u/app1/3.0。
可选参数:strategy=auto|patch|full 强制指定升级方式(一般不用传,服务端自己判断最省的那条); auto=0 表示「只查已经生成好的包,不要在服务端现算」——适合客户端做超时很短的健康检查。

③ 更新检查响应

下面是真实接口返回的完整响应(把 URL 的 ?app= 换成你的应用短码,这里就会实时显示你的应用)。

加载中…

④ 客户端升级流程

照着做就不会出错。

1 读本地版本→ 2 请求 /u/{code}?c=→ 3 看 updateAvailable→ 4 下载 recommended→ 5 校验 sha256→ 6 覆盖 + 删 removed→ 7 写新版本号
  1. 读本地版本号
    从你自己放的 version.txt / 注册表 / 配置文件里读,格式随意(3.0、3.01、3.1.1 都行)。第一次装的新用户别跳过升级检查,否则永远不知道自己不是最新。
  2. 请求更新检查接口
    GET {base}/u/{code}?c={当前版本}。记得 URL 编码版本号;超时建议 15~30 秒;失败就静默跳过,别弹错误框挡住用户启动。
  3. 判断要不要升
    updateAvailable === false → 结束。注意服务端已经做过版本比较,客户端不要自己再比一次(版本号写法歧义太多,容易比错)。
  4. 下载推荐的那个包
    优先用 recommended;它是 null 时再退到 full。下载到临时文件,并显示进度。包可能几十到几百 MB,用流式下载(ResponseHeadersRead / stream),别一次性读进内存。
  5. 校验 sha256
    算下载文件的 sha256,与 recommended.sha256 比(忽略大小写)。不一致就删掉重下一次,连续失败就提示用户用「修复」。
  6. 解压到临时目录再覆盖
    先把 zip 解到临时目录,再把 files/ 下的内容覆盖到安装目录; 然后按 removed 删文件(必须先做路径穿越校验:路径里含 .. 就跳过)。 千万不要边解压边覆盖 —— 中途失败会留下半个版本。
  7. 记下新版本号并收尾
    把本地版本号写成响应里的 latest(或包内 update.json 的 to,两者一致)。 删掉临时文件。如果升级包里含正在运行的可执行文件,先退出主进程再替换,或替换后用 「重命名旧文件 + 写新文件 + 下次启动清理」的方式绕过文件占用。
升级包会变重吗?不会。跨版本时服务端是从你的版本直接 diff 到最新版的, 只装「这两个版本之间变化过的文件」。如果变化的文件太多、增量包已经接近完整包, 服务端会自动改推完整包(strategy=full),因为这时候多个步骤只会更容易出错。 也就是说:你永远不需要自己决定用增量还是完整。

⑤ 升级包结构

升级包就是一个 zip,固定两样东西,增量包和完整包结构完全一样。

包.zip
├─ update.json          ← 元数据:版本、要写哪些文件、要删哪些文件、目标版本全量清单
└─ files/               ← 真正要覆盖到安装目录的内容(保持原相对路径)
   ├─ App.exe
   ├─ lib/core.dll
   └─ docs/readme.md

update.json 字段

字段含义与用法
typepatch 增量包 / full 完整包。客户端处理方式完全一致,不用分支。
from / to起始版本 / 目标版本。完整包的 from 是 null。to 就是升完之后的版本号。
payloadDir载荷目录名,固定 files。用它拼路径,别写死字符串。
files[]本包携带的文件 {path, sha256, size}。要写入的清单(增量包只有变化过的)。
removed[]要删除的相对路径。旧版有、新版没有的文件都在这。完整包恒为空。
manifest[]目标版本的全量文件清单(路径 + sha256 + 大小)。这是「升完就是最新版」的证据:覆盖 + 删除后逐条比对即可确认。
stats统计信息(文件数、payload 大小、完整包大小、省下的比例),可用来展示。
包里 files/ 和 removed 都为空是合法的 —— 只有版本号变化时会这样。 照常走完流程、写入新版本号即可,别当成错误。

⑥ 代码示例

都是完整可用的最小实现,把 APP_CODE 换成你的短码就能跑。

加载中…

用到的命名空间:System.Net.Http、System.IO.Compression(需 System.IO.Compression.FileSystem)、System.Security.Cryptography、System.Text.Json。

⑦ 「修复」按钮

装坏了、文件被删了、版本对不上,用户点它就能回到官方最新状态。

修复接口

这个接口不看客户端版本,永远返回最新完整包的直链(full.url)。 完整包自带全量清单,所以修复逻辑比升级更简单:

  1. 调 /r/{code}
    拿到 full.url / full.sha256 / fileCount(将恢复多少个文件)。
  2. 下载 + 校验 sha256
    与升级完全一样。界面可以提示「正在修复(1/2 下载)…」。
  3. 解压,用 files/ 覆盖安装目录
    这一步会把缺失或损坏的文件全部补回来。不要删用户数据目录,只覆盖程序本体。
  4. 版本号写成 full.to
    修复后就是最新版了。
要不要顺手删掉多余文件?完整包的 removed 是空的,服务端不会让你去删东西。 如果想做一个「彻底干净」的修复,可以先拉 /m/{code} 拿到官方全量清单, 把安装目录里不在清单中的文件删掉 —— 但要排除用户数据、存档、配置、日志、插件目录, 否则会把用户的东西删掉。默认建议不要做这件事。

只想补缺失文件(省流量版修复)

调 /m/{code} 拿清单,逐个算本地文件的 sha256:一致的跳过,缺失或对不上的记下来。 若缺失文件总量很小,可以只从完整包里取这几个文件覆盖(完整包仍然是 zip,解压后按需取用即可)。 包体积不大的应用没必要这么麻烦,直接整包覆盖最稳。

⑧ 校验与兜底

三层保险,按需要挑。

哪一层做什么必要性
包级校验 下载完算整个 zip 的 sha256,与 recommended.sha256 比对。 必做
文件级校验 覆盖完成后,按包内 update.json 的 manifest 逐条算本地文件 sha256 比对(或只抽查关键文件)。 推荐
版本自检 / 自愈 启动时调 /m/{code},本地抽检发现缺失或损坏 → 自动走「修复」流程静默补回。 推荐
降级 / 回滚 升级失败时把临时目录里备份的旧文件还原,保持原版本可运行,下次再试。 建议
升级前先退出主进程 / 释放文件占用。Windows 上正在运行的 exe 和 dll 是删不掉也换不掉的。 常见做法:① 升级程序独立成 Updater.exe,主程序调用它后自己退出,由它完成替换再启动主程序; ② 或者下载到临时目录,注册「下次启动前替换」的钩子。

⑨ 常见问题

客户端版本号写得很乱(3.0 / 3.01 / 3.1)会不会认错? 不会。服务端会把它们归一化成严格三段式再比较:3.0 → 3.0.0、3.01 → 3.0.1、3.1 → 3.1.0、3.11 → 3.1.1。唯一的歧义是 3.10 会等于 3.1,位号接近 10 时请写成三段式 3.10.0。
客户端版本太老,服务端没有它的记录怎么办? 服务端算不出增量包,会直接把 strategy 置为 full 并给出完整包。reason 里会写明原因。客户端不需要写特殊分支,照常下载 recommended 即可。
用户很久没升级,跨了十几个版本,会不会升不到最新? 会升到最新。增量包是从你的版本直接 diff 到最新版的,与中间隔了几版无关。recommended.to 恒等于 latest。
为什么有时候给的是完整包而不是增量包? 因为变化的文件太多,增量包已经接近(甚至超过)完整包的大小。这时完整包更小、步骤更少、出错机会更少,服务端就自动改推完整包。响应里的 plan.reason 会写清楚,例如「增量包只比完整包小 1.2 MB,不值得多走一步」。
接口需要登录吗?可以放在客户端里吗? 更新检查、修复、清单三个接口都是公开免登录的,可以直接写进客户端。管理接口(上传/删除/统计)才需要登录,记得别把管理密码打进客户端。
响应字段以后会变吗?会不会不兼容? 老的 patch / full 字段永久保留、语义不变。新字段只增不改。所以客户端可以放心依赖 recommended / steps,也可以继续用老字段。
下载地址换了域名怎么办? 不要写死域名拼路径。直接用响应里给的完整 url(已经是当前域名),换域名/换短码都不用改客户端。
能不能只升级增量的「二进制差」而不是整个文件? 当前是整文件增量(变化过的文件整份发),不是字节级差分。它的好处是客户端实现极简、不需要 bsdiff 之类的外部工具,跨版本也不会出现「补丁打不上」。如果你的应用里有几个特别大的文件(几百 MB)偶尔只改一点点,可以把它单独拆成一个更新通道再走整文件增量。
怎么调试? 浏览器里直接打开更新检查地址(把 {当前版本} 换成真版本号)就能看到完整 JSON;控制台里也能看到每个应用的短码、直链和包体积。reason 字段会用人话解释服务端为什么这么选包。

本页地址可以直接分享给做客户端的同事:
/guide