gin框架 上传文件

web 程序中有时候需要处理上传文件,通常由前端负责提交文件,后端负责处理或者保存文件。

gin 框架内置了处理文件上传的方法,包括 单个文件,多个文件以及特定文件特殊文件的处理。

1. 上传单个文件

gin 框架中,multipart/form-data 格式用于文件上。文件上传与原生的 net/http 方法类似,不同在于 gin 把原生的 request 封装到 c.Request 中。

前端 html 文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">
          上传文件:<input type="file" name="file" >
          <input type="submit" value="提交">
    </form>
</body>
</html>

文件可以保存为 test.html。

后端 go 文件:

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    engine := gin.Default()
    //限制上传最大尺寸
    engine.MaxMultipartMemory = 8 << 20
    engine.POST("/upload", func(c *gin.Context) {
        file, err := c.FormFile("file")
        if err != nil {
            c.String(500, "上传图片出错")
        }
        // c.JSON(200, gin.H{"message": file.Header.Context})
        c.SaveUploadedFile(file, file.Filename)
        c.String(http.StatusOK, file.Filename)
    })
    engine.Run()
}

运行程序后,浏览器访问 test.html文件,就可以在浏览器中上传文件。

2. 上传特定文件

有的用户上传文件需要限制上传文件的类型以及上传文件的大小,但是 gin 框架暂时没有这些函数。因此,我们基于原生的函数写了一个可以限制大小以及文件类型的上传函数。

package main

import (
    "fmt"
    "log"
    "net/http"
    "github.com/gin-gonic/gin"
)

func main() {
    engine := gin.Default()
    engine.POST("/upload", func(c *gin.Context) {
        _, headers, err := c.Request.FormFile("file")
        if err != nil {
            log.Printf("Error when try to get file: %v", err)
        }
        //headers.Size 获取文件大小
        if headers.Size > 1024*1024*2 {
            fmt.Println("文件太大了")
            return
        }
        //headers.Header.Get("Content-Type")获取上传文件的类型
        if headers.Header.Get("Content-Type") != "image/png" {
            fmt.Println("只允许上传png图片")
            return
        }
        c.SaveUploadedFile(headers, "./video/"+headers.Filename)
        c.String(http.StatusOK, headers.Filename)
    })
    engine.Run()
}

3. 上传多个文件

前端 html 文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">
          上传文件:<input type="file" name="files" multiple>
          <input type="submit" value="提交">
    </form>
</body>
</html>

文件可以保存为 test.html。

package main

import (
   "github.com/gin-gonic/gin"
   "net/http"
   "fmt"
)

func main() {
   engine := gin.Default()
   // 限制表单上传大小 8MB,默认为32MB
   engine.MaxMultipartMemory = 8 << 20
   engine.POST("/upload", func(c *gin.Context) {
      form, err := c.MultipartForm()
      if err != nil {
         c.String(http.StatusBadRequest, fmt.Sprintf("get err %s", err.Error()))
      }
      // 获取所有图片
      files := form.File["files"]
      // 遍历所有图片
      for _, file := range files {
         // 逐个保存
         if err := c.SaveUploadedFile(file, file.Filename); err != nil {
            c.String(http.StatusBadRequest, fmt.Sprintf("upload err %s", err.Error()))
            return
         }
      }
      c.String(200, fmt.Sprintf("upload ok %d files", len(files)))
   })
 
   engine.Run()
}

运行程序后,浏览器访问 test.html文件,就可以在浏览器中上传文件。

下一章:gin框架 路由分组

我们在使用 web 框架开发时,经常会根据业务逻辑给一个模块划分一组路由。把一个模块相关的方法都写在一个路由下,主要好处是业务逻辑清晰,便于管理和查找相关的代码。路由分组语法:gin 框架支持路由分组(routes group),路由分组的关键词为 group。路由分组的范例:gin 框架支持路由分组(routes group),路由分组的关键词为 group。