断点续传必须基于file_token+total_size+client_id三元组校验;上传前客户端计算全文件sha256,服务端据此匹配已传分片并校验每片哈希;分片读取需用seekg与gcount严格控界;失败后须查询服务端状态再决定重传或清空重来。

分片上传前必须校验文件是否被修改
大文件上传中途失败再续传,最怕用户在暂停后偷偷改了文件内容。MD5 或 SHA256 校验不是可选项,是断点续传成立的前提。只比对文件名或大小,upload_id 会失效,服务端根本不敢信任已传的分片。
- 客户端上传前先计算整个文件的
sha256sum(用内存映射 + 分块读取,避免 OOM),作为file_token发给服务端 - 服务端收到首请求时,检查该
file_token是否已有未完成上传;若有,直接返回已传分片列表,不新建任务 - 每次上传分片时,客户端必须附带该
file_token和当前分片的偏移量offset、长度size,服务端按此定位并校验分片哈希(如 SHA256(file[offset:offset+size]))
用 std::ifstream 配合 seekg 安全读取分片
C++ 没有现成的“分片流”抽象,得自己控制读取边界。直接用 read() 不设限容易越界,尤其文件被截断或并发修改时,gcount() 返回值必须校验。
- 打开文件用
std::ios::binary模式,否则 Windows 下换行符会被误转 - 每次分片上传前调用
ifs.seekg(offset, std::ios::beg),之后立即检查ifs.fail()—— 若offset超出当前文件大小,seekg会静默失败 - 用
ifs.read(buffer, chunk_size)后,立刻用ifs.gcount()获取真实读取字节数,它可能小于chunk_size(比如最后一片),不能直接当完整分片发出去
服务端如何判断“同一文件”的续传请求
光靠前端传来的 file_name 或 upload_id 不可靠:重名文件、浏览器缓存旧 ID、用户刷新页面都会导致歧义。真正能锚定上传会话的是三元组:file_token + total_size + 客户端生成的稳定 client_id(如 UUIDv4)。
-
file_token保证内容一致;total_size排除截断/追加干扰;client_id防止不同设备用同一文件 token 冲突 - 服务端存储分片元数据时,主键应为
(file_token, client_id, chunk_index),而非upload_id—— 后者应在首次请求时由服务端生成并返回,仅供前端临时引用 - 若收到新请求的
file_token已存在但total_size不同,直接拒绝,返回错误"file_size_mismatch"
断点续传失败时,客户端怎么安全回退
网络中断、磁盘满、权限丢失都可能导致单个分片上传失败。此时不能简单重试,更不能删掉已传分片——得让服务端和客户端状态严格对齐。
立即学习“C++免费学习笔记(深入)”;
- 客户端每次上传分片后,必须等待服务端明确返回
{"status":"success","chunk_index":5}才算落库成功;超时或 HTTP 非 2xx 一律视为失败 - 失败后,客户端立即发起
GET /upload/status?file_token=xxx&client_id=yyy查询当前服务端已确认的分片列表,而不是依赖本地缓存 - 若服务端返回的已传列表为空或不连续,说明元数据损坏,客户端应触发完整重传流程(清空本地记录,从 index 0 开始),而不是盲目跳过“看起来已传”的分片
最难缠的其实是时钟不同步导致的 last_modified 时间戳错乱,或者 NFS 文件系统下 stat() 返回陈旧 size —— 这些地方没法靠逻辑兜住,只能靠 file_token 强一致性来覆盖。










