Revel 不支持断点续传,需手动封装 HTTP 流处理:绕过框架响应逻辑,用 http.ServeContent 实现 Range 支持;前端负责切片、MD5 校验与状态查询;服务端须用 Redis 等持久化进度,避免 Session 存储。

Revel 本身不支持断点续传,必须自己封装 HTTP 流处理
Revel 框架没有内置 Range 头解析、206 Partial Content 响应或分块上传状态管理。它的 c.File() 和 c.Data() 都走完整响应流程,会返回 200 OK 并忽略客户端的 Range 请求——这意味着浏览器或下载器根本不会发起断点请求。
服务端必须用 http.ServeContent 替代 Revel 封装逻辑
要让 Revel 支持断点下载,唯一可靠方式是绕过框架的响应封装,直接操作底层 http.ResponseWriter:
- 先调用
c.Writer.WriteHeader(http.StatusOK)清空 Revel 的 header 缓存(否则后续设置无效) - 手动设置关键 header:
c.Header("Accept-Ranges", "bytes")(必需,否则客户端不发Range) - 确保
Content-Type和Content-Disposition正确,避免触发浏览器默认行为 - 用
http.ServeContent(w, r, filename, modtime, reader),其中reader必须是io.ReadSeeker(如*os.File) -
size参数必须是文件真实字节长度,不能用os.Stat().Size()后就不管——若文件正被并发写入,会返回错误的416 Range Not Satisfiable
前端上传侧需独立实现切片与 fileId 校验
Revel 对上传侧完全无特殊支持,所有断点续传逻辑都得前端承担:
- 切片必须用
file.slice(start, Math.min(file.size, start + shardSize)),末片边界错一个字节就会漏传 -
fileId必须基于内容计算 MD5(推荐spark-md5),不能拼接name + size——Revel 路由和控制器不参与这个校验,全靠你前端发/upload/status?fileId=xxx查询已传索引 - 每片
FormData必须带chunkIndex、totalChunks、fileId,Revel 控制器里要靠这三个字段定位临时存储位置 - 单片 Blob 不宜超过 5MB;超大会在 Chrome 中触发
RangeError: Maximum call stack size exceeded,且 JS 引擎可能把整个 Blob 加载进内存导致页面假死
进度状态不能存在 Revel Session 或 Cookie 里
Revel 默认的 session 存储(如加密 cookie)不适合存上传进度:
- 进度数据体积大(比如 1GB 文件分 200 片,数组就几百字节),cookie 有大小限制且每次请求都携带,浪费带宽
- 多设备/隐私模式下 localStorage 可能失效,得用 try/catch 降级到内存对象,但重启即丢——所以服务端必须持久化,比如用 Redis 存
uploadedChunks数组 - Revel 的
c.Session.Set()是同步写入,不适合高频更新的上传状态;应改用外部缓存或数据库,由控制器显式调用
最易被忽略的是:Revel 的中间件和路由层对 Range 请求头完全透明,你写了 Accept-Ranges: bytes 也得确保没其他中间件(比如 gzip、CORS)覆盖或干扰 header 写入顺序——一旦 header 被提前 flush,http.ServeContent 就会失效。


















