【问题标题】:Using MultipartRequest to upload file使用 MultipartRequest 上传文件
【发布时间】:2019-10-08 03:07:00
【问题描述】:

我正在使用 Goa v3 设计一个端点,允许我使用 multipart/form-data POST 请求上传文件(更准确地说是图像)。 我已经声明了以下Service

var _ = Service("images", func() {
    HTTP(func() {
        Path("/images")
    })

    Method("upload", func() {  
        HTTP(func() {
            POST("/")
            MultipartRequest()
        })

        Payload(func() {
            Description("Multipart request Payload")
            Attribute("File", Bytes, "File")
        })

        Result(ImageList)
    })
})

我运行goa gengoa example 命令来生成样板代码。除了cmd目录,example代码生成images.go主文件和multipart.go文件来声明编码器和解码器逻辑,例如:

func ImagesUploadDecoderFunc(mr *multipart.Reader, p **images.UploadPayload) error {
    // Add multipart request decoder logic here
    return nil
}

我可以使用mr.NextPart() 并获得对图像文件的引用,但我仍然不确定如何将其映射到images.UploadPayload 类型中的Bytes 字段(或者我应该声明另一种类型的字段来处理文件??)。

我在 Goa 文档中找不到任何示例。

【问题讨论】:

    标签: go goa


    【解决方案1】:

    好的,我终于明白multipart.Reader 的工作原理了,我想出了一个解决方案。

    首先让我们澄清一下,与 Goa 通常的工作方式不同(使用 Payload 字段“自动”映射请求参数),使用 MultipartRequest(),我必须自己进行映射,所以 Payload 可以实际上有任何结构。

    在我的例子中,我重新定义了我的Payload 结构如下:

    // ImageUpload single image upload element
    var ImageUpload = Type("ImageUpload", func() {
        Description("A single Image Upload type")
        Attribute("type", String)
        Attribute("bytes", Bytes)
        Attribute("name", String)
    })
    
    // ImageUploadPayload is a list of files
    var ImageUploadPayload = Type("ImageUploadPayload", func() {
        Description("Image Upload Payload")
    
        Attribute("Files", ArrayOf(ImageUpload), "Collection of uploaded files")
    })
    

    简而言之,我想支持上传多个文件,每个文件都有自己的 mime 类型、文件名和数据。

    为此,我实现了multipart.go 解码器功能,如下所示:

    func ImagesUploadDecoderFunc(mr *multipart.Reader, p **images.ImageUploadPayload) error {
        res := images.ImageUploadPayload{}
    
        for {
            p, err := mr.NextPart()
            if err == io.EOF {
                break
            }
    
            if err != nil {
                fmt.Fprintln(os.Stderr, err)
                return err
            }
    
            _, params, err := mime.ParseMediaType(p.Header.Get("Content-Disposition"))
            if err != nil {
                // can't process this entry, it probably isn't an image
                continue
            }
    
            disposition, _, err := mime.ParseMediaType(p.Header.Get("Content-Type"))
            // the disposition can be, for example 'image/jpeg' or 'video/mp4'
            // I want to support only image files!
            if err != nil || !strings.HasPrefix(disposition, "image/") {
                // can't process this entry, it probably isn't an image
                continue
            }
    
            if params["name"] == "file" {
                bytes, err := ioutil.ReadAll(p)
                if err != nil {
                    // can't process this entry, for some reason
                    fmt.Fprintln(os.Stderr, err)
                    continue
                }
                filename := params["filename"]
                imageUpload := images.ImageUpload{
                    Type:  &disposition,
                    Bytes: bytes,
                    Name:  &filename,
                }
                res.Files = append(res.Files, &imageUpload)
            }
        }
        *p = &res
        return nil
    }
    

    【讨论】:

      猜你喜欢
      • 2013-01-03
      • 1970-01-01
      • 1970-01-01
      • 2021-10-25
      • 1970-01-01
      • 2014-08-15
      • 1970-01-01
      • 2019-02-16
      • 2011-08-16
      相关资源
      最近更新 更多