# v0 断点续传：上传中断后按真实 offset 接着传，最后核对文件哈希

作者本地 HTTP 服务与浏览器已实际完成半途停止、错误 Offset 409、刷新后 HEAD 从 262144 续传，以及 524288 字节 SHA256 一致。v0 账号生成会话和云部署未运行。

## 环境



## 启动

~~~sh
cd reference
python3 server.py --port 8787
# 浏览器打开 http://127.0.0.1:8787
~~~

## 七步操作

1. 准备原创输入与本地服务

下载练习包，先阅读 TASK.md。输入由 Uint8Array 按固定公式生成，总长 524288 字节；它不来自你的私人文件。reference 是作者完成的本地浏览器与 HTTP 参考，starter 留给你在 v0 中独立实现。

进入 reference 运行 python3 server.py --port 8787，再打开 http://127.0.0.1:8787。此时进度为零。保留开发者工具 Network，稍后核对真正的请求与响应。

2. 向 v0 交付完整协议合同

把“创建上传、每块提交、刷新恢复、拒绝错误偏移、最终哈希”作为完整合同交给 v0。要求生成前后端配合代码，而不是仅有百分比动画；界面可以替换，协议字段与字节验收必须保留。

请求 v0 实现的任务提示见下方。本文未运行 v0 账号生成会话；下载的作者参考可直接运行，原生 HTTP 和浏览器链路已验证。

3. 分块传到一半并停止

点击“创建并传一半”。POST /uploads 用 Upload-Length 声明总长，响应 Location 指向独立上传 ID。随后四个 PATCH 各发 65536 字节，到 262144 字节主动停止。

每次 PATCH 都带 Tus-Resumable: 1.0.0、Content-Type: application/offset+octet-stream 和当前 Upload-Offset。服务端返回的新 Offset 必须与已存字节相等，不信任前端百分比。

4. 拒绝错误 Offset

停在一半时点“发送错误 Offset”。参考故意以 Offset 0 再提交一字节，真实响应为 409，Upload-Offset 仍为 262144。错误请求不能覆写已收到的内容。

上传状态存在这个练习服务器进程内，页面只保存练习 ID。此实现用于观察 tus 基本字节协议；关闭服务器会清空练习状态。

5. 刷新后先 HEAD 再续传

刷新页面，然后点“HEAD 后续传”。新页面先对同一上传地址发送 HEAD，读取服务端 Upload-Offset: 262144，再发送余下四块。即使前端内存丢失，传输起点仍由服务器决定。

请在页面记录里确认第一个恢复请求是 HEAD，后续 PATCH 起点为 262144。不能根据本地缓存的数字直接从头重传，也不能把 HTTP 状态未知当作上传完成。

6. 核对完整长度与哈希

完成后服务器应保存 524288 字节。参考同时对原始 Uint8Array 和已存服务端字节计算 SHA256，两边完整哈希一致，原始值见下方代码块。

长度相同仍可能传错内容，所以必须同时比较完整哈希。此哈希是作者额外的结果核对，不代表实现了 tus 可选 Checksum 扩展。

7. 复现并确认协议范围

重新启动练习服务并从零重复整条链路，核对半途停止、409 拒绝、刷新 HEAD、最终长度与哈希。你也可以替换为自己的原创小文件，先同步声明长度与预期哈希。

上线前需要自行设计鉴权、额度、持久化、多进程并发和过期清理；本题只实现单进程教学环境中的 tus 基本创建及续传流程，未验证 v0 云部署。

## 目录身份

- starter：待完成的任务接口与原创输入，TODO不是已完成实现。
- reference：作者原生完成参考和实际产物。records.json/browser-result.json为本地实测记录，不是AI助手回复。
- TASK.md：可交给相应AI助手的原始任务合同。该助手账号生成会话未运行。

## 依赖与许可

原创教学代码以MIT许可提供。第三方项目、模型及浏览器遵循其自身许可。第三方依赖由本地安装获取，不包含node_modules、模型权重、WASM运行时、数据库、缓存或凭据。

## 官方依据

- https://tus.io/protocols/resumable-upload
