简体   繁体   English

如何在 go gin 中获取从 JSON 发布的文件?

[英]How to get file posted from JSON in go gin?

I want to save image file posted by JSON.我想保存由 JSON 发布的图像文件。

Here is the struct of the post:这是帖子的结构:

type Article struct {
    Title   string `json:"title"`
    Body string `json:"body"`
    File    []byte `json:"file"`
}

And the handler is:处理程序是:

   func PostHandler(c *gin.Context) {
        var err error
        var json Article
        err = c.BindJSON(&json)
        if err != nil {
            log.Panic(err)
        }

    //handle photo upload
        var filename string
        file, header, err := json.File  //assignment count mismatch: 3 = 1

        if err != nil {
            fmt.Println(err)
            filename = ""

        } else {
            data, err := ioutil.ReadAll(file)
            if err != nil {
                fmt.Println(err)
                return
            }

            filename = path.Join("media", +shared.RandString(5)+path.Ext(header.Filename))

            err = ioutil.WriteFile(filename, data, 0777)
            if err != nil {
                io.WriteString(w, err.Error())
                return
            }

        }
...

But I get但我明白了

assignment count mismatch: 3 = 1分配计数不匹配:3 = 1

I copied the file handling part from a working multipart form handler which worked fine but apparently,我从一个工作正常的多部分表单处理程序中复制了文件处理部分,但显然,

file, header, err := r.FormFile("uploadfile")

can not be translated into JSON handling.不能翻译成JSON处理。

I have looked at gin docs but could not find examples involving json file handling.我查看了 gin 文档,但找不到涉及 json 文件处理的示例。 So how can I fix this?那么我该如何解决呢?

Using Gin to get an uploaded file使用 Gin 获取上传的文件

I think your question is "Using Gin, how do I get an uploaded file?".我认为您的问题是“使用 Gin,如何获取上传的文件?”。 Most developers don't upload files with JSON encoding, which could be done but requires the file to be included as a base64 string (and increases the file size about 33%).大多数开发人员不上传使用 JSON 编码的文件,这可以做到,但需要将文件作为 base64 字符串包含在内(并增加文件大小约 33%)。

The common (and more efficient) practice is to upload the file using the "multipart/form-data" encoding.常见(且更有效)的做法是使用“multipart/form-data”编码上传文件。 The code that others provided file, header, err:= c.Request.FormFile("file") works, but that hijacks the underlining "net/http" package that Gin extends.其他人提供的代码file, header, err:= c.Request.FormFile("file")有效,但它劫持了 Gin 扩展的下划线“net/http”包。

My recommendation is to use ShouldBind , but you can also use the FormFile orMultipartForm methods provided by the Gin package.我的建议是使用ShouldBind ,但您也可以使用 Gin 包提供的FormFileMultipartForm方法。

Examples below.下面的例子。 Similar (but less detailed) explanations are also offered on the Gin page https://github.com/gin-gonic/gin#model-binding-and-validation and https://github.com/gin-gonic/gin#upload-files . Gin 页面https://github.com/gin-gonic/gin#model-binding-and-validationhttps://github.com/gin-gonic/gin#上也提供了类似(但不太详细)的解释上传文件


Upload one file上传一个文件


Clients客户

HTML HTML

<form action="/upload" method="POST">
  <input type="file" name="file">
  <input type="submit">
</form>

Curl卷曲

curl -X POST http://localhost:8080/upload \
  -F "file=../path-to-file/file.zip" \
  -H "Content-Type: multipart/form-data"

Server服务器

Go

package main

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

type Form struct {
    File *multipart.FileHeader `form:"file" binding:"required"`
}

func main() {
    router := gin.Default()

    // Set a lower memory limit for multipart forms (default is 32 MiB)
    // router.MaxMultipartMemory = 8 << 20  // 8 MiB

    router.POST("/upload", func(c *gin.Context) {

        // Using `ShouldBind`
        // --------------------
        var form Form
        _ := c.ShouldBind(&form)

        // Get raw file bytes - no reader method
        // openedFile, _ := form.File.Open()
        // file, _ := ioutil.ReadAll(openedFile)

        // Upload to disk
        // `form.File` has io.reader method
        // c.SaveUploadedFile(form.File, path)
        // --------------------

        // Using `FormFile`
        // --------------------
        // formFile, _ := c.FormFile("file")

        // Get raw file bytes - no reader method
        // openedFile, _ := formFile.Open()
        // file, _ := ioutil.ReadAll(openedFile)

        // Upload to disk
        // `formFile` has io.reader method
        // c.SaveUploadedFile(formFile, path)
        // --------------------
        
        c.String(http.StatusOK, "Files uploaded")
    })

    // Listen and serve on 0.0.0.0:8080
    router.Run(":8080")
}

Upload multiple files上传多个文件


Clients客户

HTML HTML

<form action="/upload" method="POST" multiple="multiple">
  <input type="file" name="files">
  <input type="submit">
</form>

Curl卷曲

curl -X POST http://localhost:8080/upload \
  -F "files=../path-to-file/file1.zip" \
  -F "files=../path-to-file/file2.zip" \
  -H "Content-Type: multipart/form-data"

Server服务器

Go

package main

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

type Form struct {
    Files []*multipart.FileHeader `form:"files" binding:"required"`
}

func main() {
    router := gin.Default()

    // Set a lower memory limit for multipart forms (default is 32 MiB)
    // router.MaxMultipartMemory = 8 << 20  // 8 MiB

    router.POST("/upload", func(c *gin.Context) {

        // Using `ShouldBind`
        // --------------------
        var form Form
        _ := c.ShouldBind(&form)

        // for _, formFile := range form.Files {

          // Get raw file bytes - no reader method
          // openedFile, _ := formFile.Open()
          // file, _ := ioutil.ReadAll(openedFile)

          // Upload to disk
          // `formFile` has io.reader method
          // c.SaveUploadedFile(formFile, path)

        // }
        // --------------------

        // Using `MultipartForm`
        // --------------------
        // form, _ := c.MultipartForm()
        // formFiles, _ := form["files[]"]

        // for _, formFile := range formFiles {

          // Get raw file bytes - no reader method
          // openedFile, _ := formFile.Open()
          // file, _ := ioutil.ReadAll(openedFile)

          // Upload to disk
          // `formFile` has io.reader method
          // c.SaveUploadedFile(formFile, path)

        // }
        // --------------------
        
        c.String(http.StatusOK, "Files uploaded")
    })

    // Listen and serve on 0.0.0.0:8080
    router.Run(":8080")
}

In your code you say var json Article where type article is defined as在您的代码中,您说var json Article类型文章定义为

type Article struct {
    Title   string `json:"title"`
    Body string `json:"body"`
    File    []byte `json:"file"`
}

And File is of type []byte . File 是[]byte类型。 Type byte doesn't return anything other than what it holds类型 byte 除了它所持有的内容外不返回任何东西

Your Article.File is not the same as r.FormFile where FormFile is a method that returns 3 items您的Article.Filer.FormFile ,其中FormFile是返回 3 个项目的方法

So file, header, err:= json.File isn't file, header, err:= r.FormFile("foo")所以file, header, err:= json.File不是file, header, err:= r.FormFile("foo")

See the implementation and method description from godocs -> here请参阅 godocs ->此处的实现和方法描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM