目录
  • 前言
  • 使用原生net/http库实现文件上传
  • 使用Gin实现文件上传
    • 单个文件上传
      • FormFile()获取文件
      • SaveUploadedFile()保存到本地 
      • 设置缓冲区大小
      • 限制文件大小
      • 限制文件类型
      • 完整示例
      • 测试文件上传
    • 多个文件上传
      • MultipartForm()获取多个文件
      • 测试文件上传
  • 总结

    前言

    今天我们来聊聊如何使用Gin实现文件上传。

    Go标准库net/http对文件上传已经提供了非常完善的支持,而Gin框架在其基础上进一步封装,因此使用Gin开发文件上传功能时,只需要简单几行代码便可以实现,Gin框架支持单个文件与多个文件同时上传。

    使用原生net/http库实现文件上传

    我们首先看看实现一个HTTP服务器,提供文件上传功能的简单示例

    package main
     
    import (
        "io"
        "io/ioutil"
        "log"
        "net/http"
     
        "github.com/julienschmidt/httprouter"
    )
     
    const (
        MAX_UPLOAD_SIZE = 1024 * 1024 * 20 //最大上传大小,50MB
    )
     
    func main() {
        r := RegisterHandlers()
     
        http.ListenAndServe(":8080", r)  // 开启一个http服务
    }
     
    // 定义路由
    func RegisterHandlers() *httprouter.Router {
        router := httprouter.New()
     
        router.POST("/upload", uploadHandler)
     
        return router
    }
    // 文件上传接口
    func uploadHandler(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
        r.Body = http.MaxBytesReader(w, r.Body, MAX_UPLOAD_SIZE)
        if err := r.ParseMultipartForm(MAX_UPLOAD_SIZE); err != nil {
            log.Printf("File is too big")
            return
        }
        file, headers, err := r.FormFile("file")
        if err != nil {
            log.Printf("Error when try to get file: %v", err)
            return
        }
        //获取上传文件的类型
        if headers.Header.Get("Content-Type") != "image/png" {
            log.Printf("只允许上传png图片")
            return
        }
        data, err := ioutil.ReadAll(file)
        if err != nil {
            log.Printf("Read file error: %v", err)
            return
        }
        fn := headers.Filename
        err = ioutil.WriteFile("./video/"+fn, data, 0666)
        if err != nil {
            log.Printf("Write file error: %v", err)
            return
        }
        w.WriteHeader(http.StatusCreated)
        io.WriteString(w, "Uploaded successfully")
    }

    如上我们通过r.FormFile函数获取上传的文件对象,以及文件的相关信息。然后通过headers.Header.Get函数获取上传文件的类型,判断类型是否符合要求。接着,使用ioutil.ReadAll函数读取文件的内容,并将其存储在data变量中。然后,通过headers.Filename获取上传文件的文件名,并使用ioutil.WriteFile函数将文件内容写入到指定路径下的文件中。

    使用Gin实现文件上传

    单个文件上传

    FormFile()获取文件

    单文件上传使用gin.ContextFormFile()方法,该方法的值为POST请求中文件上传字段的名称:

     engine := gin.Default()
     engine.POST("/upload", func(c *gin.Context) {
         file, err := c.FormFile("file")
     })
     engine.Run()

    SaveUploadedFile()保存到本地 

    调用gin.ContextSaveUploadedFile()方法可以将文件保存到某个目录下:

     dst := "./uploads/" + file.Filename
     c.SaveUploadedFile(file,"./uploadFile")

    设置缓冲区大小

    Go默认文件上传缓冲区为32M,当有大量文件上传时,服务器内存的压力会很大,因此可以通过MaxMultipartMemory属性来设置缓冲区大小:

     //8M
     engine.MaxMultipartMemory = 8 << 20

    限制文件大小

    上传文件时,不限制文件大小可以会导致服务存储空间暴涨,因为有必须限制上传文件大小:

     fileMaxSize := 4 << 20 //4M
     if int(file.Size) > fileMaxSize {
       c.String(http.StatusBadRequest, "文件不允许大小于4M")
       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
     }

    在上面的代码中,我们读取文件的前512个字节,再调用http.DetectContentType()便可以获取文件的MIME值。

    完整示例

     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 -F "file=@./1.jpg" -X POST "http://localhost:8080/upload"
     '1.jpg' 上传成功!

    多个文件上传

    MultipartForm()获取多个文件

    如果要上传多个文件,多次调用gin.ContextFormFile()方法也是可以的,但更好的方式是使用gin.ContextMultipartForm()方法:

     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命令上传多个文件:

    $ curl -F "upload=@./1.jpg" -F "upload=@./2.jpg" -X POST "http://localhost:8080/uploadMul
    2 files uploaded

    总结

    Go标准库net/http对文件上传已经提供了非常完善的支持,可以满足我们大部分需求,Gin框架在其基础做了封装,让我们使用起来更加方便迅速。

    以上就是Golang使用Gin实现文件上传的示例代码的详细内容,更多关于Golang Gin文件上传的资料请关注其它相关文章!

    声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。