1

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!

1 Answer 1

2

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()
    ...
Sign up to request clarification or add additional context in comments.

2 Comments

Oh ok I did not understood correctly from the docs then. I though r.MultipartForm directly contained all the keys for each file and iterating that would give me all the file, but it was not like that. Your solution works like a charm, thanks!
@NicolaM94 The Request.Form* methods are helpers that return the first value after ensuring the form is parsed. These functions are not the primary access to the data.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.