必须采用分片上传机制处理超大文件,前端用File API切片并校验,后端保存临时分片及元数据,合并时校验哈希、顺序拼接,支持断点续传与自动清理。

在处理用户上传超大文件(如视频、工程包、数据库备份)时,单次HTTP请求容易因超时、内存溢出或网络中断导致失败,必须采用分片上传机制保障成功率和用户体验。
前端分片与校验
使用 JavaScript 的 File API 将原始文件切分为固定大小的 Blob 片段(建议 2–5MB/片),按顺序编号并携带唯一 uploadId:
const file = document.getElementById('fileInput').files[0];
const chunkSize = 5 * 1024 * 1024;
const chunks = [];
for (let i = 0; i chunks.push(file.slice(i, i + chunkSize));
}
每片上传前计算 SHA-256 哈希值,作为该片的指纹,后端将用它校验完整性。不要跳过这步——【缺少哈希校验的分片上传无法识别传输损坏】。
上传时携带三个关键参数:uploadId(客户端生成的 UUID)、chunkNumber(从 1 开始递增)、totalChunks(总片数)。
后端接收与暂存
控制器中定义 actionUploadChunk 方法,接收单个分片:
public function actionUploadChunk()
{
$uploadId = Yii::$app->request->post('uploadId');
$chunkNumber = (int)Yii::$app->request->post('chunkNumber');
$totalChunks = (int)Yii::$app->request->post('totalChunks');
$file = UploadedFile::getInstanceByName('file');
}
将分片保存到临时目录(如 @runtime/uploads/chunks/{uploadId}/),文件名格式为 {chunkNumber}.bin。注意:不要直接写入最终路径,避免未完成上传就触发业务逻辑。
同时记录该 uploadId 的元数据(总片数、已接收片数、各片哈希值)到缓存(Redis)或数据库临时表,有效期设为 24 小时。
合并与验证
当收到最后一片(chunkNumber === totalChunks)时,触发合并流程:
第一步:按 chunkNumber 升序读取所有 .bin 文件;
第二步:逐片比对客户端提交的 SHA-256 与本地计算值,任一不匹配即中止并返回错误;
第三步:使用 file_put_contents() 配合 FILE_APPEND 标志拼接成完整文件;
第四步:删除所有临时分片文件及缓存元数据。
合并成功后,调用业务逻辑处理文件(如转码、解析、入库),并将最终文件路径存入数据库。
若某片上传失败或超时,前端可依据 chunkNumber 重传,后端无需重复存储——【同 uploadId + 同 chunkNumber 的请求会覆盖旧片】。
断点续传支持
方法一:前端发起 /check-status 请求,传 uploadId,后端返回已接收的 chunkNumber 数组;
方法二:前端在上传前先 GET /upload-info?uploadId=xxx,后端查缓存返回 totalChunks 和 receivedChunks;
方法三:更健壮的做法是让前端维护本地 localStorage 记录每个 uploadId 的已传片号,仅在页面刷新后才调用方法一补全状态。
服务端无需主动轮询或心跳保活,靠 uploadId 缓存 TTL 自动清理失效任务。



















