为了账号安全,请及时绑定邮箱和手机立即绑定

如何处理同时具有多个输入和多个文件的请求

如何处理同时具有多个输入和多个文件的请求

Go
青春有我 2022-09-12 20:35:18
构建一个后端 go 服务器,该服务器可以采用具有多个输入的形式,其中 3 个具有多个文件输入。我搜索了一下,它指出,如果你想做这样的东西,你不想使用典型的if err := r.ParseMultipartForm(32 << 20); err != nil {        fmt.Println(err)    }    // get a reference to the fileHeaders    files := r.MultipartForm.File["coverArt"]相反,您应该使用mr, err := r.MultipartReader()    if err != nil {        http.Error(w, err.Error(), http.StatusInternalServerError)    }标准表单数据:名字电子邮件封面图片照片(多个文件)个人资料照片(多个文件)2 音频文件 (2 歌曲)2个视频(个人介绍,无伴奏合唱中的人物录音)表单<form method="post" enctype="multipart/form-data" action="/upload">        <input type="text" name="name">        <input type="text" name="email">        <input name="coverArt" type="file"  multiple />        <input name="profile" type="file"  multiple />        <input type="file" name="songs"  multiple />        <input type="file" name="videos"  multiple/>        <button type="submit">Upload File</button> </form>转到代码:func FilePOST(w http.ResponseWriter, r *http.Request) error {    fmt.Println("File Upload Endpoint Hit")    mr, err := r.MultipartReader()    if err != nil {        http.Error(w, err.Error(), http.StatusInternalServerError)    }        for {        part, err := mr.NextPart()        // This is OK, no more parts        if err == io.EOF {            break        }        // Some error        if err != nil {            http.Error(w, err.Error(), http.StatusInternalServerError)                  }转到服务器错误: 去运行 main.go [15:58:21] 现在在以下位置提供服务 www.localhost:3000 文件上传端点 命中信息[0009] POST /上传已过=“680.422μs” 主机 = 方法 = POST 路径=/上传查询= 2021/07/14 15:58:32 http: 恐慌服务 [::1]:62924: 运行时错误: 无效的内存地址或 nil 指针取消引用
查看完整描述

1 回答

?
喵喵时光机

TA贡献1846条经验 获得超7个赞

很难猜测你的代码在哪里恐慌。原因可能是您的程序在发生错误时继续执行。例如,如果创建文件失败,将死机,因为 为零。outfile.Close()outfile


这两种方法都支持单个字段的多个文件。不同之处在于它们如何处理内存。流式处理版本从网络读取一小部分数据,并在您调用 时将其写入文件。另一个变体在您调用 时将所有数据加载到内存中,因此它需要与要传输的文件大小一样多的内存。您将在下面找到两种变体的工作示例。io.CopyParseMultiForm()


流媒体变体:


func storeFile(part *multipart.Part) error {

    name := part.FileName()

    outfile, err := os.Create("uploads/" + name)

    if err != nil {

        return err

    }

    defer outfile.Close()

    _, err = io.Copy(outfile, part)

    if err != nil {

        return err

    }

    return nil

}


func filePOST(w http.ResponseWriter, r *http.Request) error {

    fmt.Println("File Upload Endpoint Hit")

    mr, err := r.MultipartReader()

    if err != nil {

        return err

    }

    for {

        part, err := mr.NextPart()


        // This is OK, no more parts

        switch {

        case errors.Is(err, io.EOF):

            fmt.Println("done")

            return nil

        case err != nil:

            // Some error

            return err

        default:

            switch part.FormName() {

            case "coverArt", "profile", "songs", "videos":

                if err := storeFile(part); err != nil {

                    return err

                }

            }

        }

    }

}


func main() {

    http.HandleFunc("/upload", func(writer http.ResponseWriter, request *http.Request) {

        err := filePOST(writer, request)

        if err != nil {

            http.Error(writer, err.Error(), http.StatusInternalServerError)

            log.Println("Error", err)

        }

    })

    if err := http.ListenAndServe(":8080", nil); err != nil {

        log.Fatal(err)

    }

}

版本带有 ,它将数据读取到内存。ParseMultipartForm


func storeFile(part *multipart.FileHeader) error {

    name := part.Filename

    infile, err := part.Open()

    if err != nil {

        return err

    }

    defer infile.Close()

    outfile, err := os.Create("uploads/" + name)

    if err != nil {

        return err

    }

    defer outfile.Close()

    _, err = io.Copy(outfile, infile)

    if err != nil {

        return err

    }

    return nil

}


func FilePOST(w http.ResponseWriter, r *http.Request) error {

    fmt.Println("File Upload Endpoint Hit")

    if err := r.ParseMultipartForm(2 << 24); err != nil {

        return err

    }

    for _, fileType := range []string{"coverArt", "profile", "songs", "videos"} {

        uploadedFiles, exists := r.MultipartForm.File[fileType]

        if !exists {

            continue

        }

        for _, file := range uploadedFiles {

            if err := storeFile(file); err != nil {

                return err

            }

        }

    }

    return nil

}


func main() {

    http.HandleFunc("/upload", func(writer http.ResponseWriter, request *http.Request) {

        err := FilePOST(writer, request)

        if err != nil {

            http.Error(writer, err.Error(), http.StatusInternalServerError)

            log.Println("Error", err)

        }

    })

    if err := http.ListenAndServe(":8080", nil); err != nil {

        log.Fatal(err)

    }

}


查看完整回答
反对 回复 2022-09-12
  • 1 回答
  • 0 关注
  • 76 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信