公众号:程序员读书,欢迎关注
在之前的文章中,我们讲解了在Gin
框架中获取参数的几种方式,这几种方式获取的都是字符串,除了字符串,我们也可以获取客户端上传的文件。
Gin
框架支持单个文件与多个文件同时上传。
单个文件上传
单文件上传使用gin.Context
的FormFile()
方法,该方法的值为POST
请求中文件上传字段的名称:
css
engine := gin.Default()
engine.POST("/upload", func(c *gin.Context) {
file, err := c.FormFile("file")
})
engine.Run()
调用gin.Context
的SaveUploadedFile()
方法可以将文件保存到某个目录下:
css
dst := "./uploads/" + file.Filename
c.SaveUploadedFile(file,"./uploadFile")
Go默认文件上传缓冲区为32M
,当有大量文件上传时,服务器内存的压力会很大,因此可以通过MaxMultipartMemory
属性来设置缓冲区大小:
ini
//8M
engine.MaxMultipartMemory = 8 << 20
上传文件时,不限制文件大小可以会导致服务存储空间暴涨,因为有必须限制上传文件大小:
go
fileMaxSize := 4 << 20 //4M
if int(file.Size) > fileMaxSize {
c.String(http.StatusBadRequest, "文件不允许大小于4M")
return
}
对文件类型,也可以进行限制:
go
reader, err := file.Open()
if err != nil {
fmt.Println(err)
return
}
b := make([]byte, 512)
reader.Read(b)
contentType := http.DetectContentType(b)
if contentType != "image/jpeg" && contentType != "image/png" {
c.String(http.StatusOK, "文件格式错误")
return
}
在上面的代码中,我们读取文件的前512
个字节,再调用http.DetectContentType()
便可以获取文件的MIME
值。
关于文件大小、类型等限制,下面是一个完整的示例:
go
package main
import (
"fmt"
"log"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
engine := gin.Default()
//8M
engine.MaxMultipartMemory = 8 << 20
engine.POST("/upload", func(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
log.Println(err)
c.String(http.StatusBadRequest, "文件上传失败")
return
}
fileMaxSize := 4 << 20 //4M
if int(file.Size) > fileMaxSize {
c.String(http.StatusBadRequest, "文件不允许大小于32KB")
return
}
reader, err := file.Open()
if err != nil {
fmt.Println(err)
return
}
b := make([]byte, 512)
reader.Read(b)
contentType := http.DetectContentType(b)
if contentType != "image/jpeg" && contentType != "image/png" {
c.String(http.StatusOK, "文件格式错误")
return
}
dst := "./uploads/" + file.Filename
c.SaveUploadedFile(file, dst)
c.String(http.StatusOK, fmt.Sprintf("'%s' 上传成功!", file.Filename))
})
engine.Run()
}
运行程序后,使用curl
命令上传文件:
ruby
$ curl -F "file=@./1.jpg" -X POST "http://localhost:8080/upload"
'1.jpg' 上传成功!
多个文件上传
如果要上传多个文件,多次调用gin.Context
的FormFile()
方法也是可以的,但更好的方式是使用gin.Context
的MultipartForm()
方法:
go
package main
import (
"fmt"
"log"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
engine := gin.Default()
engine.POST("/uploadMul", func(c *gin.Context) {
form, err := c.MultipartForm()
if err != nil {
log.Println(err)
c.String(http.StatusBadRequest, "文件上传失败")
return
}
files := form.File["upload"]
for _, file := range files {
fmt.Println(file.Filename)
}
c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
})
engine.Run()
}
运行程序后,使用curl
命令上传多个文件:
ini
$ curl -F "upload=@./1.jpg" -F "upload=@./2.jpg" -X POST "http://localhost:8080/uploadMul
2 files uploaded
多文件上传有关于文件类型、大小限制等设置,都与单个文件上传类型一样,可以参与单文件上传的完整案例。
小结
Go标准库net/http
对文件上传已经提供了非常完善的支持,而Gin
框架在其基础上进一步封装,因此使用Gin
开发文件上传功能时,只需要简单几行代码便可以实现。