Gin 如何实现单个文件上传
Gin 框架中的文件上传其实引用的是 Go 标准库 net/http
的文件上传方式。不过呢,Gin 自己也封装了一个 gin.Context.SaveUploadedFile()
用于保存文件
file, err := c.FormFile("file") // 获取上传的文件 // 处理 err filename := filepath.Base(file.Filename) // 获取文件名 err = c.SaveUploadedFile(file, filename) // 保存文件 // 处理 error
更多内容可以参考 Github issue #774 和 example code.
注意
file.Filename
是不可信的。
file.Filename
并不总是存在且有正确的值。而且存在上传漏洞,不要盲目使用。 如果要使用原始的文件名,那么推荐的做法是使用filepath.Base(file.Filename)
得到正确的文件名后再用。
示例
目录结构如图
├── go.mod ├── go.sum ├── main.go ├── public └── index.html
main.go
package main import ( "net/http" "path/filepath" "github.com/gin-gonic/gin" ) func main() { router := gin.Default() // 为 multipart forms 设置较低的内存限制 (默认是 32 MiB) router.MaxMultipartMemory = 8 << 20 // 8 MiB router.Static("/", "./public") router.POST("/upload", func(c *gin.Context) { name := c.PostForm("name") email := c.PostForm("email") // 单文件 file, err := c.FormFile("file") if err != nil { c.String(http.StatusBadRequest, "get form err: %s", err.Error()) return } filename := filepath.Base(file.Filename) // 上传文件至指定的完整文件路径 if err := c.SaveUploadedFile(file, filename); err != nil { c.String(http.StatusBadRequest, "upload file err: %s", err.Error()) return } c.String(http.StatusOK, "File %s uploaded successfully with fields name=%s and email=%s.", file.Filename, name, email) }) router.Run(":8080") }
public/index.html
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Single file upload</title> </head> <body> <h1>Upload single file with fields</h1> <form action="/upload" method="post" enctype="multipart/form-data"> Name: <input type="text" name="name"><br> Email: <input type="email" name="email"><br> Files: <input type="file" name="file"><br><br> <input type="submit" value="Submit"> </form> </body>
Gin 服务运行后,你可以使用下面的 cURL 命令来测试
How to curl
:
curl -X POST http://localhost:8080/upload \ -F "file=@/Users/appleboy/test.zip" \ -H "Content-Type: multipart/form-data"
有关 Content-Disposition
的内容,你可以阅读 Content-Disposition
on MDN 和 Github issue #1693