vue.jsgofile-uploadclient-servermultifile-uploader

Can't parse multiple files with Go MultipartForm


I'm building a simple file uploader, basically for learning/testing purposes, using Vue for the front-end and Go for the back-end. Here's the code

<template>
    <div class="adddocument-container">
        <h1>Trascina il documento da aggiungere qui</h1>
        <form action="http://localhost:55678/postdocument" method="post" enctype="multipart/form-data" style="display: flex;flex-direction: column;gap: 20px;">
        <input class="fileinput" name="file[]" ref="file" type="file" multiple @input="collectDocument">
        <div>
            <p v-for="i in it"> {{ i.name }}</p>
        </div>
        <button type="submit">Upload</button>
        </form>        
    </div>
</template>

<script>
export default {
    data () {
        return {
            it : []
        }
    },
    methods : {
        collectDocument() {
            this.it = this.$refs.file.files
        }
    }
}
</script>

And golang http handler function here:

package handlers

import (
    "io"
    "os"
    "mlpbackend/dbmanager"
    "net/http"
)

func PostDocument (db *dbmanager.DBClient) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
    
        r.ParseMultipartForm(0)
        
        for k := range r.MultipartForm.File {
            
            file,fileheader,err := r.FormFile(k)
                
                if err != nil {
                    panic(err)
                }
                defer file.Close()
                
                localFileName := "./documents/" + fileheader.Filename
                out, err := os.Create(localFileName)
                if err != nil {
                    panic(err)
                }
                defer out.Close()
                _, err = io.Copy(out,file)
                if err != nil {
                    panic(err)
                }   
        }
    }
}

It seems I can't receive/parse more than one file in the back-end, and I can't understand why or where I am wrong. Basically, the go handler should write all the files received in the documents folder, but it only writes (correctly) the last one selected in the front-end.

Also, I checked the POST request sent from the front-end and it seems it correctly sends all the files (I'm basing this assumption on the request size), but I don't understand where I am wrong in the back-end at this point.

Thank you very much for any help!


Solution

  • The documentation for Request.FormFile says:

    FormFile returns the first file for the provided form key.

    The application must use the Request's MultipartForm directly to access all files for the key.

    for k, fileheaders := range r.MultipartForm.File {
        for _, fileheader := range fileheaders {
            file, err := fileheader.Open()
            if err != nil {
                panic(err)
            }
            defer file.Close()
            ...
    

    The application can access all files for the key file[] as follows. There's no need to loop over keys as in the question.

    fileheaders := r.MultipartForm.File["file[]"]
    for _, fileheader := range fileheaders {
        file, err := fileheader.Open()
        if err != nil {
            panic(err)
        }
        defer file.Close()
        ...