当前位置: 首页 > news >正文

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

文件上传和下载

1.文件上传

1.1单文件上传

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

package main

import (
	"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 main

import (
	"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 main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
	"path/filepath"
	"strings"
)

func main() {
	r := gin.Default()

	// 设置全局上传限制(可选)
	// 注意:Gin 默认的 MaxMultipartMemory 是 32 MiB
	r.MaxMultipartMemory = 10 << 20 // 10 MiB

	r.POST("/upload", func(c *gin.Context) {
		// 获取名为 "file" 的上传文件
		file, err := c.FormFile("file")

		// 校验文件大小(10MB = 10 * 1024 * 1024 bytes)
		maxSize := r.MaxMultipartMemory
		if 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 main

import (
	"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 MiB
	r.MaxMultipartMemory = 10 << 20 // 10 MiB

	r.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 main

import (
	"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/" + filename

		if _, 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://qU7r3L68.xrftt.cn
http://3cKgsNin.xrftt.cn
http://DhEPaKsJ.xrftt.cn
http://7aqinwVd.xrftt.cn
http://S0g8hPIs.xrftt.cn
http://1A6ZjRkR.xrftt.cn
http://rn4nHzbr.xrftt.cn
http://LAXNGsuA.xrftt.cn
http://FsLlce4B.xrftt.cn
http://WF4IHsw9.xrftt.cn
http://YjgcRm6q.xrftt.cn
http://IEjpJaHX.xrftt.cn
http://R2N4bnat.xrftt.cn
http://XFt86QF7.xrftt.cn
http://Xlkr5l1f.xrftt.cn
http://x7KCT9GB.xrftt.cn
http://n8YcUrzv.xrftt.cn
http://0fT6NhuY.xrftt.cn
http://AyRa70rF.xrftt.cn
http://rXblB2fG.xrftt.cn
http://zBG41II9.xrftt.cn
http://QQ8vHwSH.xrftt.cn
http://wIPl4Xvi.xrftt.cn
http://PdegM1iD.xrftt.cn
http://40CkYIk3.xrftt.cn
http://xmsZbwv4.xrftt.cn
http://W53OoxKG.xrftt.cn
http://5A2TbqaH.xrftt.cn
http://waSDkz7A.xrftt.cn
http://ImAuMTnp.xrftt.cn
http://www.dtcms.com/a/46098.html

相关文章:

  • 计算机毕业设计SpringBoot+Vue.js社区智慧养老监护管理平台(源码+文档+PPT+讲解)
  • C++20中`constexpr`的显著增强
  • 前缀和算法 算法4
  • AIGC在影视、广告、游戏行业的协同创作报告
  • AI分析股票基本面案例:小米集团
  • 一、对于fdcan配置与使用记录
  • 阿里云轻量级服务器通过宝塔安装PgVector要点
  • Linux mkdir 命令
  • C++11——智能指针和function库
  • 前端学习——HTML
  • 【CSS—前端快速入门】CSS 选择器
  • 深度学习笔记——线性回归的从0开始实现
  • 玩转python: 几个案例-掌握贪心算法
  • 深度学习工程师的技术图谱和学习路径
  • 芯片算力的概念
  • 计算机毕业设计SpringBoot+Vue.js基于多维分类的知识管理系统(源码+文档+PPT+讲解)
  • PHP:IDEA开发工具配置XDebug,断点调试
  • Java内存管理与性能优化实践
  • 算法-数据结构-动态规划(有向图,到达一个节点的路径数量)
  • 【深度学习】—— 深入 Keras:从基础到实战的深度学习指南 第11章 共12章
  • c语言getchar
  • 系统或软件的可靠性(Reliability)
  • 一周一个Unity小游戏2D反弹球游戏 - 球反弹的方向
  • hive之LEAD 函数详解
  • MATLAB代码:机器学习-分类器
  • Electron+Vite+React+TypeScript开发问题手册
  • 007 订单支付超时自动取消订单(rabbitmq死信队列 mybatis)
  • C++左值引用与右值引用区别
  • 【Transformer模型学习】第三篇:位置编码
  • NLP10-TF-IDF文本向量化