Go语言实现大文件分片上传与断点续传功能
作者:枫叶V
在现代 Web 应用中,大文件上传是一个常见需求,为了解决这些痛点,通常采用 分片上传 与 断点续传 的方案,本文将带你使用 Go 实现一个简易的大文件分片上传与断点续传服务,希望对大家有所帮助
在现代 Web 应用中,大文件上传是一个常见需求。直接上传大文件会遇到网络中断、上传超时、失败后无法续传等问题。为了解决这些痛点,通常采用 分片上传 与 断点续传 的方案。
本文将带你使用 Go 实现一个简易的大文件分片上传与断点续传服务。
核心思路
1.分片上传
将大文件切分成多个小块(chunk),逐块上传,避免单次上传过大失败。
2.断点续传
每个文件有唯一的标识(如 MD5、UUID),服务端记录已上传的分片信息,上传中断后可继续上传剩余分片。
.3合并分片
当所有分片上传完成后,服务端将这些分片按顺序合并成完整文件。
服务端实现
上传接口设计
- 初始化上传:生成 uploadId,返回客户端。
- 上传分片:
/upload/chunk?uploadId=xxx&chunkIndex=1
- 合并分片:所有分片传完后,调用
/upload/merge
合并。
Go 代码示例
package main import ( "fmt" "io" "net/http" "os" "path/filepath" "strconv" ) // 临时存放分片目录 const uploadDir = "./uploads" func main() { // 创建目录 os.MkdirAll(uploadDir, os.ModePerm) http.HandleFunc("/upload/chunk", uploadChunkHandler) http.HandleFunc("/upload/merge", mergeChunksHandler) fmt.Println("服务已启动: http://localhost:8080") http.ListenAndServe(":8080", nil) } // 上传分片 func uploadChunkHandler(w http.ResponseWriter, r *http.Request) { uploadId := r.URL.Query().Get("uploadId") chunkIndex := r.URL.Query().Get("chunkIndex") if uploadId == "" || chunkIndex == "" { http.Error(w, "缺少参数", http.StatusBadRequest) return } // 保存分片目录 chunkDir := filepath.Join(uploadDir, uploadId) os.MkdirAll(chunkDir, os.ModePerm) // 分片文件路径 chunkPath := filepath.Join(chunkDir, chunkIndex) // 写入文件 file, err := os.Create(chunkPath) if err != nil { http.Error(w, "无法保存分片", http.StatusInternalServerError) return } defer file.Close() _, err = io.Copy(file, r.Body) if err != nil { http.Error(w, "写入分片失败", http.StatusInternalServerError) return } w.Write([]byte("分片上传成功: " + chunkIndex)) } // 合并分片 func mergeChunksHandler(w http.ResponseWriter, r *http.Request) { uploadId := r.URL.Query().Get("uploadId") totalChunks := r.URL.Query().Get("totalChunks") if uploadId == "" || totalChunks == "" { http.Error(w, "缺少参数", http.StatusBadRequest) return } chunkDir := filepath.Join(uploadDir, uploadId) mergedFile := filepath.Join(uploadDir, uploadId+"_merged") // 创建目标文件 dst, err := os.Create(mergedFile) if err != nil { http.Error(w, "无法创建合并文件", http.StatusInternalServerError) return } defer dst.Close() // 合并分片 chunkCount, _ := strconv.Atoi(totalChunks) for i := 1; i <= chunkCount; i++ { chunkPath := filepath.Join(chunkDir, strconv.Itoa(i)) src, err := os.Open(chunkPath) if err != nil { http.Error(w, fmt.Sprintf("缺少分片 %d", i), http.StatusBadRequest) return } _, err = io.Copy(dst, src) src.Close() if err != nil { http.Error(w, "合并失败", http.StatusInternalServerError) return } } w.Write([]byte("文件合并完成: " + mergedFile)) }
客户端实现思路
前端/客户端需要
- 将文件分割为多个 固定大小的 chunk。
- 顺序调用 /upload/chunk 上传分片。
- 上传完成后调用 /upload/merge 合并文件。
- 如果上传中断,查询已上传分片,从断点继续。
示例伪代码:
async function uploadFile(file) { const chunkSize = 5 * 1024 * 1024; // 5MB const totalChunks = Math.ceil(file.size / chunkSize); const uploadId = generateUploadId(file); // 可用 MD5/UUID for (let i = 0; i < totalChunks; i++) { const start = i * chunkSize; const end = Math.min(file.size, start + chunkSize); const chunk = file.slice(start, end); let formData = new FormData(); formData.append("file", chunk); await fetch(`/upload/chunk?uploadId=${uploadId}&chunkIndex=${i+1}`, { method: "POST", body: chunk }); } await fetch(`/upload/merge?uploadId=${uploadId}&totalChunks=${totalChunks}`); }
优化点
分片校验:上传前计算 MD5,避免重复上传。
并行上传:可同时并发上传多个分片,提升速度。
断点续传:服务端保存已上传分片信息,客户端查询后跳过已完成分片。
秒传功能:通过文件 Hash 判断文件是否已存在,直接返回完成。
总结
通过 Go 实现大文件分片上传与断点续传,可以有效提升上传成功率和用户体验。实际项目中,还需要结合 数据库记录、鉴权、并发控制、文件存储(如 OSS、S3、MinIO) 等功能,构建更健壮的文件上传系统。
到此这篇关于Go语言实现大文件分片上传与断点续传功能的文章就介绍到这了,更多相关Go大文件上传内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!