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

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://www.kler.cn/a/560384.html

相关文章:

  • 自定义SpringBoot Starter
  • 1.✨Java学习笔记
  • Win10登录Samba服务器报用户名密码错误问题解决
  • Windows 11【1001问】如何下载Windows 11系统镜像
  • 安装可视化jar包部署平台JarManage
  • 【排序算法】堆排序详解
  • 金融行业数据安全:KSP密钥管理系统如何保障支付交易与客户信息零泄露
  • springcloud负载均衡策略有哪些
  • 芯谷D1308:低成本、高性能的便携式音频解决方案
  • 【数据处理】COCO 数据集掩码 Run-Length Encoding (RLE) 编码转二进制掩码
  • UE5 Gameplay框架及继承关系详解
  • WPF基本布局基础
  • 【无人集群系列---大疆无人集群技术进展、技术路线与未来发展方向】
  • Hi3516CV610开发板ISP调试之——图像ISP在线调试 环境搭建教程
  • 理解CompletableFuture的非阻塞
  • springboot005学生心理咨询评估系统(源码+数据库+文档)
  • 使用Vue-Flow创建一个流程图可视化节点坐标查询器
  • 【算法】位运算
  • 4. Spring Cloud Gateway 入门与使用
  • 牛客周赛 Round 82(思维、差分、树状数组、大根堆、前后缀、递归)