upload
在 Go 的 Gin 框架中,处理文件上传是一个常见的需求。Gin 提供了简便的 API 来处理文件上传,支持单文件上传和多文件上传。
1. 基本的文件上传
1.1 单个文件上传
以下是一个最简单的示例,展示如何使用 Gin 接收单个文件并保存到本地磁盘。
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
// 上传文件路由
r.POST("/upload", func(c *gin.Context) {
// 获取表单中的文件,"file" 是上传文件的字段名称
file, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "File upload failed",
})
return
}
// 保存文件到指定路径
err = c.SaveUploadedFile(file, "./uploads/"+file.Filename)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": "Unable to save file",
})
return
}
// 返回成功消息
c.JSON(http.StatusOK, gin.H{
"message": fmt.Sprintf("File %s uploaded successfully", file.Filename),
})
})
// 启动服务
r.Run(":8080")
}1.2 解释
c.FormFile("file"):从请求的表单数据中获取上传的文件,file是前端表单中<input type="file" name="file">的字段名。c.SaveUploadedFile(file, "./uploads/"+file.Filename):将上传的文件保存到指定路径。这里的file.Filename是客户端上传的文件名,建议你确保上传路径是安全的,并且该文件名不会覆盖已有文件。
1.3 前端 HTML 表单
前端的文件上传表单示例:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Upload</title>
</head>
<body>
<form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">
<label for="file">Choose a file:</label>
<input type="file" name="file" id="file" required>
<button type="submit">Upload</button>
</form>
</body>
</html>2. 多个文件上传
Gin 也支持处理多个文件上传。通过 c.MultipartForm() 方法可以获取多个文件。
2.1 多个文件上传示例
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
// 上传多个文件路由
r.POST("/upload_multiple", func(c *gin.Context) {
// 获取多个文件
form, err := c.MultipartForm()
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Unable to get form data",
})
return
}
// 获取表单中的所有文件
files := form.File["files"]
for _, file := range files {
// 保存每个文件
err := c.SaveUploadedFile(file, "./uploads/"+file.Filename)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": "Unable to save file",
})
return
}
}
// 返回成功消息
c.JSON(http.StatusOK, gin.H{
"message": fmt.Sprintf("%d files uploaded successfully", len(files)),
})
})
// 启动服务
r.Run(":8080")
}2.2 前端 HTML 表单(多个文件)
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Multiple File Upload</title>
</head>
<body>
<form action="http://localhost:8080/upload_multiple" method="post" enctype="multipart/form-data">
<label for="files">Choose files:</label>
<input type="file" name="files" id="files" multiple required>
<button type="submit">Upload</button>
</form>
</body>
</html>3. 文件大小限制
为了防止上传过大的文件影响服务器性能,Gin 提供了设置文件大小限制的功能。在启动 Gin 引擎时,可以通过 gin.Default() 配置最大文件大小。
3.1 设置最大文件大小限制
go
r := gin.Default()
// 设置最大上传文件大小为 10 MB
r.MaxMultipartMemory = 10 << 20 // 10 MB
r.POST("/upload", func(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "File upload failed",
})
return
}
// 保存文件
err = c.SaveUploadedFile(file, "./uploads/"+file.Filename)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": "Unable to save file",
})
return
}
// 返回成功消息
c.JSON(http.StatusOK, gin.H{
"message": fmt.Sprintf("File %s uploaded successfully", file.Filename),
})
})这样就设置了最大文件上传大小为 10 MB,超过此大小的文件会触发 http.StatusRequestEntityTooLarge 错误。
4. 处理上传的文件类型
如果你只希望接收某些类型的文件(例如只接受图片文件),可以通过 mime.TypeByExtension() 来验证文件类型。
4.1 限制文件类型
go
r.POST("/upload", func(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "File upload failed",
})
return
}
// 检查文件类型
ext := file.Filename[len(file.Filename)-4:]
if ext != ".jpg" && ext != ".png" && ext != ".jpeg" {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Invalid file type, only .jpg, .jpeg, .png are allowed",
})
return
}
// 保存文件
err = c.SaveUploadedFile(file, "./uploads/"+file.Filename)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": "Unable to save file",
})
return
}
// 返回成功消息
c.JSON(http.StatusOK, gin.H{
"message": fmt.Sprintf("File %s uploaded successfully", file.Filename),
})
})5. 上传进度和反馈
Go 本身没有直接提供上传进度的 API,但是你可以通过流式传输和一些中间件来实现上传进度的反馈。可以通过定期检查文件大小和已上传字节数来实现进度条。
6. 总结
- 单文件上传:通过
c.FormFile()获取上传的文件,并使用c.SaveUploadedFile()保存文件。 - 多文件上传:通过
c.MultipartForm()获取上传的多个文件。 - 文件大小限制:使用
r.MaxMultipartMemory设置文件上传的最大大小。 - 文件类型检查:通过文件后缀名或 MIME 类型来限制允许上传的文件类型。