当前位置: 首页 > 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)

相关文章:

  • 计算机毕业设计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章
  • 三亚婚纱摄影 织梦网站源码/中国联通和腾讯
  • 兰州做网站维护的公司/成都sem优化
  • 网站建设合同法/镇江推广公司
  • 郑州网站制作哪家便宜/怎么推广自己的网站
  • b2c交易平台/江西网络推广seo
  • asp网站做搜索/在线seo优化