乐闻世界logo
搜索文章和话题

Gin 框架中如何实现文件上传和下载?

2月21日 15:16

Gin 框架中的文件上传和下载实现方法如下:

1. 文件上传

1.1 单文件上传

go
func uploadFile(c *gin.Context) { file, err := c.FormFile("file") if err != nil { c.JSON(400, gin.H{"error": err.Error()}) return } // 保存文件 dst := "./uploads/" + file.Filename if err := c.SaveUploadedFile(file, dst); err != nil { c.JSON(500, gin.H{"error": err.Error()}) return } c.JSON(200, gin.H{ "message": "File uploaded successfully", "filename": file.Filename, "size": file.Size, }) }

1.2 多文件上传

go
func uploadMultipleFiles(c *gin.Context) { form, err := c.MultipartForm() if err != nil { c.JSON(400, gin.H{"error": err.Error()}) return } files := form.File["files"] var uploadedFiles []string for _, file := range files { dst := "./uploads/" + file.Filename if err := c.SaveUploadedFile(file, dst); err != nil { c.JSON(500, gin.H{"error": err.Error()}) return } uploadedFiles = append(uploadedFiles, file.Filename) } c.JSON(200, gin.H{ "message": "Files uploaded successfully", "files": uploadedFiles, }) }

1.3 文件大小限制

go
func uploadFileWithLimit(c *gin.Context) { // 限制文件大小为 10MB c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, 10<<20) file, err := c.FormFile("file") if err != nil { c.JSON(400, gin.H{"error": "File too large"}) return } // 处理文件上传... }

1.4 文件类型验证

go
func uploadFileWithValidation(c *gin.Context) { file, err := c.FormFile("file") if err != nil { c.JSON(400, gin.H{"error": err.Error()}) return } // 验证文件类型 allowedTypes := []string{"image/jpeg", "image/png", "image/gif"} fileHeader, err := file.Open() if err != nil { c.JSON(500, gin.H{"error": err.Error()}) return } defer fileHeader.Close() buffer := make([]byte, 512) _, err = fileHeader.Read(buffer) if err != nil { c.JSON(500, gin.H{"error": err.Error()}) return } contentType := http.DetectContentType(buffer) isAllowed := false for _, allowedType := range allowedTypes { if contentType == allowedType { isAllowed = true break } } if !isAllowed { c.JSON(400, gin.H{"error": "Invalid file type"}) return } // 处理文件上传... }

2. 文件下载

2.1 简单文件下载

go
func downloadFile(c *gin.Context) { filename := c.Param("filename") filepath := "./uploads/" + filename c.File(filepath) }

2.2 带自定义文件名的下载

go
func downloadFileWithCustomName(c *gin.Context) { filename := c.Param("filename") filepath := "./uploads/" + filename c.FileAttachment(filepath, "custom-name.pdf") }

2.3 流式下载

go
func downloadFileStream(c *gin.Context) { filename := c.Param("filename") filepath := "./uploads/" + filename file, err := os.Open(filepath) if err != nil { c.JSON(404, gin.H{"error": "File not found"}) return } defer file.Close() fileInfo, _ := file.Stat() c.Header("Content-Disposition", "attachment; filename="+filename) c.Header("Content-Type", "application/octet-stream") c.Header("Content-Length", strconv.FormatInt(fileInfo.Size(), 10)) http.ServeContent(c.Writer, c.Request, filename, fileInfo.ModTime(), file) }

2.4 断点续传下载

go
func downloadFileWithResume(c *gin.Context) { filename := c.Param("filename") filepath := "./uploads/" + filename file, err := os.Open(filepath) if err != nil { c.JSON(404, gin.H{"error": "File not found"}) return } defer file.Close() fileInfo, _ := file.Stat() // 处理 Range 请求 rangeHeader := c.GetHeader("Range") if rangeHeader != "" { // 解析 Range 头 ranges := strings.Split(rangeHeader, "=")[1] parts := strings.Split(ranges, "-") start, _ := strconv.ParseInt(parts[0], 10, 64) file.Seek(start, 0) remaining := fileInfo.Size() - start c.Header("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, fileInfo.Size()-1, fileInfo.Size())) c.Header("Content-Length", strconv.FormatInt(remaining, 10)) c.Header("Accept-Ranges", "bytes") c.Status(206) // Partial Content io.CopyN(c.Writer, file, remaining) return } c.Header("Accept-Ranges", "bytes") http.ServeContent(c.Writer, c.Request, filename, fileInfo.ModTime(), file) }

3. 最佳实践

3.1 文件存储

  • 使用专门的存储服务(如 OSS、S3)
  • 文件名使用 UUID 或时间戳避免冲突
  • 按日期或用户分目录存储

3.2 安全考虑

  • 验证文件类型和大小
  • 扫描上传的文件(病毒检测)
  • 限制上传目录的访问权限
  • 对敏感文件进行加密

3.3 性能优化

  • 使用流式处理大文件
  • 实现断点续传
  • 使用 CDN 加速文件下载
  • 启用 gzip 压缩

3.4 错误处理

  • 提供清晰的错误信息
  • 记录上传下载日志
  • 实现重试机制

通过以上方法,可以实现安全、高效的文件上传和下载功能。

标签:Gin