Gin从入门到精通 (七)文件上传和下载

ops/2025/2/28 19:23:29/

文件上传和下载

1.文件上传

1.1单文件上传

在 Gin 中处理单文件上传,可以使用 c.FormFile 方法获取上传的文件,然后使用 c.SaveUploadedFile 方法保存文件。

package mainimport ("github.com/gin-gonic/gin""log"
)func main() {r := gin.Default()r.POST("/upload", func(c *gin.Context) {// 获取名为 "file" 的上传文件file, err := c.FormFile("file")if err != nil {c.JSON(400, gin.H{"error": err.Error()})return}// 保存上传的文件if err := c.SaveUploadedFile(file, file.Filename); err != nil {log.Println("Failed to save file:", err)c.JSON(500, gin.H{"error": "Failed to save file"})return}c.JSON(200, gin.H{"message":  "File uploaded successfully","filename": file.Filename,})})r.Run(":8080")
}

我们使用postman来提交,http://localhost:8080/upload
在这里插入图片描述

1.2多文件上传

处理多文件上传时,可以使用 c.MultipartForm 方法获取所有上传的文件。

package mainimport ("github.com/gin-gonic/gin""log"
)func main() {r := gin.Default()r.POST("/multi-upload", func(c *gin.Context) {// 获取所有上传的文件form, err := c.MultipartForm()if err != nil {c.JSON(400, gin.H{"error": err.Error()})return}files := form.File["files"]for _, file := range files {// 保存每个上传的文件if err := c.SaveUploadedFile(file, file.Filename); err != nil {log.Println("Failed to save file:", err)c.JSON(500, gin.H{"error": "Failed to save file"})return}}c.JSON(200, gin.H{"message": "Files uploaded successfully","count":   len(files),})})r.Run(":8080")
}

使用postman测试,http://localhost:8080/multi-upload
在这里插入图片描述

1.3 限制上传文件大小

Gin 默认允许上传 32 MiB 的文件,可通过 router.MaxMultipartMemory 调整:

package mainimport ("fmt""github.com/gin-gonic/gin""log""net/http""path/filepath""strings"
)func main() {r := gin.Default()// 设置全局上传限制(可选)// 注意:Gin 默认的 MaxMultipartMemory 是 32 MiBr.MaxMultipartMemory = 10 << 20 // 10 MiBr.POST("/upload", func(c *gin.Context) {// 获取名为 "file" 的上传文件file, err := c.FormFile("file")// 校验文件大小(10MB = 10 * 1024 * 1024 bytes)maxSize := r.MaxMultipartMemoryif file.Size > maxSize {c.JSON(http.StatusRequestEntityTooLarge, gin.H{"error": fmt.Sprintf("文件大小超过限制(最大 %dMB)", maxSize/(1<<20)),})return}if err != nil {c.JSON(400, gin.H{"error": err.Error()})return}//r.MaxMultipartMemory = 1 << 20 // 1 MiB// 保存上传的文件if err := c.SaveUploadedFile(file, file.Filename); err != nil {log.Println("Failed to save file:", err)c.JSON(500, gin.H{"error": "保存文件失败"})return}c.JSON(200, gin.H{"message":  "File uploaded successfully","filename": file.Filename,})})r.Run(":8080")
}

1.4 限制上传文件类型

限制文件类型很简单,就是检测上传文件后缀 , 为了避免上传可执行文最好再校验MIME 类型

package mainimport ("fmt""github.com/gin-gonic/gin""log""net/http""path/filepath""strings"
)func isAllowedType(filename string) bool {allowed := map[string]bool{".jpg": true,".png": true,}ext := strings.ToLower(filepath.Ext(filename))return allowed[ext]
}func main() {r := gin.Default()// 设置全局上传限制(可选)// 注意:Gin 默认的 MaxMultipartMemory 是 32 MiBr.MaxMultipartMemory = 10 << 20 // 10 MiBr.POST("/upload", func(c *gin.Context) {// 获取名为 "file" 的上传文件file, err := c.FormFile("file")// 在接口中调用校验if !isAllowedType(file.Filename) {c.JSON(http.StatusBadRequest, gin.H{"error": "不支持的文件类型"})return}if err != nil {c.JSON(400, gin.H{"error": err.Error()})return}//r.MaxMultipartMemory = 1 << 20 // 1 MiB// 保存上传的文件if err := c.SaveUploadedFile(file, file.Filename); err != nil {log.Println("Failed to save file:", err)c.JSON(500, gin.H{"error": "保存文件失败"})return}c.JSON(200, gin.H{"message":  "File uploaded successfully","filename": file.Filename,})})r.Run(":8080")
}

1.5 避免上传文件名冲突

为了避免文件名冲突通常使用 UUID 或时间戳重命名,这里我们演示下 uuid

安装uuid库:

go get github.com/google/uuid

具体实现:

		//<pre>  // 生成唯一文件名</pre>newFilename := uuid.New().String() + filepath.Ext(file.Filename)if err := c.SaveUploadedFile(file, newFilename); err != nil {log.Println("Failed to save file:", err)c.JSON(500, gin.H{"error": "保存文件失败"})return}

2.文件下载

2.1 单文件下载

下载很简单,使用 c.File()即可,下面是演示代码:

package mainimport ("github.com/gin-gonic/gin""net/http""os"
)func main() {r := gin.Default()// 文件下载r.GET("/download/:filename", func(c *gin.Context) {filename := c.Param("filename")filePath := "./img/" + filenameif _, err := os.Stat(filePath); os.IsNotExist(err) {c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})return}//c.Header("Content-Disposition", "attachment; filename="+filename)c.File(filePath)})r.Run(":8080")
}

2.2 设置浏览器头信息

如果你是用来图片文件,来测试上面的代码,你会发现浏览器是直接显示图片,而不是下载图片,所以我们需要使浏览器唤起下载行为。

通过 Content-Disposition 头强制浏览器下载文件(而非预览):

c.Header("Content-Type", "application/octet-stream") // 表示是文件流,唤起浏览器下载,一般设置了这个,就要设置文件名
c.Header("Content-Disposition", "attachment; filename="+filename)  用来指定下载下来的文件名
c.Header("Content-Transfer-Encoding", "binary") // 表示传输过程中的编码形式,乱码问题可能就是因为它
c.File(filePath)

http://www.ppmy.cn/ops/162047.html

相关文章

SEO炼金术(4)| Next.js SEO 全攻略

在上一篇文章 SEO炼金术&#xff08;3&#xff09;| 深入解析 SEO 关键要素 中&#xff0c;我们深入解析了 SEO 关键要素&#xff0c;包括 meta 标签、robots.txt、canonical、sitemap.xml 和 hreflang&#xff0c;并探讨了它们在搜索引擎优化&#xff08;SEO&#xff09;中的作…

为AI聊天工具添加一个知识系统 之125 详细设计之66 智能语义网络

本文要点 要点 需要了解 ”智能“的不同意义。语义学有三&#xff1a;形式语义学、词典语义学和认知语义学。下面给出本项目的设计对“智能”的所有三种语义学 划分。 1、形式语义学&#xff08;认识对象执行操作系统化&#xff0c;形式化目的-形成数据&#xff08;形成式智…

C++程序员内功修炼——Linux C/C++编程技术汇总

在软件开发的宏大版图中&#xff0c;C 语言宛如一座巍峨的高山&#xff0c;吸引着无数开发者攀登探索。而 Linux 操作系统&#xff0c;以其开源、稳定、高效的特性&#xff0c;成为了众多开发者钟爱的开发平台。将 C 与 Linux 相结合&#xff0c;就如同为开发者配备了一把无坚不…

人工智能神经网络

利用女性糖尿病人的怀孕次数、血糖、血压、皮脂厚度、胰岛素等特征通过BP神经网络来预测一个女性是否患有糖尿病&#xff0c;并且计算出模型预测的准确率。通过女性糖尿病患者的一系列特征构建一个BP神经网络模型&#xff0c;通过该模型预测一名女性患有糖尿病的概率。 main.py…

计算机毕业设计SpringBoot+Vue.js汽车销售网站(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

ubuntu终端指令集 shell编程基础(一)

磁盘指令 连接与查看&#xff1a;磁盘与 Ubuntu 有两种连接方式&#xff1b;使用ls /dev/sd*查看是否连接成功&#xff0c;通过df系列指令查看磁盘使用信息。若 U 盘已挂载&#xff0c;相关操作可能失败&#xff0c;需用umount取消挂载。磁盘操作&#xff1a;使用sudo fdisk 磁…

【每日八股】Redis篇(二):数据结构

Redis 数据类型&#xff1f; 主要有 STRING、LIST、ZSET、SET 和 HASH。 STRING String 类型底层的数据结构实现主要是 SDS&#xff08;简单动态字符串&#xff09;&#xff0c;其主要应用场景包括&#xff1a; 缓存对象&#xff1a;可以用 STRING 缓存整个对象的 JSON&…

低空经济火热,校企合作无人机低空产业技术详解

低空经济是以低空空域为依托&#xff0c;以通用航空飞行活动为核心&#xff0c;涵盖通用航空器研发制造、市场运营、综合保障以及延伸服务等全产业链的经济形态。近年来&#xff0c;随着无人机技术的快速发展和广泛应用&#xff0c;低空经济已成为备受瞩目的新兴领域。以下是对…