目录

Go Gin文件流式上传下载实战 | 避免内存溢出的高性能方案

文件上传

Go + Gin 实现文件上传保存

在业务开发过程中,经常会遇到文件上传到服务器的需求,常规的文件上传一般不会存在文件,但是当出现大文件上传时,如果代码写的不好,容易导致服务器 OOM,这时候可以使用 Go + Gin 文件上传方案,实现大文件流式上传,避免整个文件加载到内存导致 OOM 代码如下:

package main
import (
	github.com/gin-gonic/gin
)
func main(){

	r := gin.Default()

	r.Use(gin.Recovery())

	r.POST("upload",func(c *gin.Context) { // 本质上就是一个 POST 表单接口,其中 file 参数一般是固定的,可以自定义其他的前端参数
		fileHeader, err := c.FormFile("file") // 读取文件信息
		if err!=nil{
			// 响应错误信息
			return
		}
		savePath:="/home/save.png" // 文件保存的路径

		// 保存文件
		err = c.SaveUploadedFile(fileHeader, savePath)
		if err != nil {
			return nil, err
		}

	})
	r.Run(":8080")
}

几行代码即可实现大文件保存,c.SaveUploadedFile 的原理也很简单,通过流式批量读取上传的文件(一次可能就读取几M),先保存到临时文件,最后再完成保存,删除临时文件

常见错误: Q1:SaveUploadedFile报错"http: no such file"? A:检查表单enctype是否为multipart/form-data

文件下载

go + gin 实现服务器文件下载也很非常简单,代码如下:

package main
import (
	github.com/gin-gonic/gin
)
func main(){

	r := gin.Default()

	r.Use(gin.Recovery())

	r.GET("download",func(c *gin.Context) { // 本质上就是一个普通的接口,像文件名、文件路径可以作为前端参数上传
		filePath:="/home/save.png" // 文件路径
		fileName:="save.png" // 下载展示的文件名称
		
		// 设置Content-Disposition触发浏览器下载(非展示)
		c.Writer.Header().Set("Content-Disposition", "attachment; filename="+fileName)
		c.Writer.Header().Set("Content-Type", "application/octet-stream")
        
		// 下载
		c.File(filePath)

	})
	r.Run(":8080")
}

```tet-stream")
        
		// 下载
		c.File(filePath)

	})
	r.Run(":8080")
}