Not able to save uploaded file on server using GOLANG and POLYMER http: no such file

不羁岁月 提交于 2019-12-11 05:32:09

问题


I am using vaadin upload to upload files on web application with polymer. And I am using golang for back-end.

<vaadin-upload target="../upload" max-files="20" accept="application/pdf,image/*" 
method="POST"> </vaadin-upload>

I checked that encoding type used in vaadin upload is multipart/form-data. My golang code is below.

func upload(w http.ResponseWriter, r *http.Request) {
    fmt.Println("method:", r.Method)
    if r.Method == "GET" {
        crutime := time.Now().Unix()
        h := md5.New()
        io.WriteString(h, strconv.FormatInt(crutime, 10))
        token := fmt.Sprintf("%x", h.Sum(nil))

        t, _ := template.ParseFiles("upload.gtpl")
        t.Execute(w, token)
    } else {
        r.ParseMultipartForm(32 << 20)
        file, handler, err := r.FormFile("uploadFile")
        if err != nil {
            fmt.Println(err)
            return
        }
        defer file.Close()
        fmt.Fprintf(w, "%v", handler.Header)
        f, err := os.OpenFile("./test/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
        if err != nil {
            fmt.Println(err)
            return
        }
        defer f.Close()
        io.Copy(f, file)
    }
}

It gives error on server side http: no such file. I checked this error is returned by FormFile when the provided file field name is either not present in the request or not a file field.

How do I correct my form file name. Although everything seems fine on front-end


回答1:


Did a quick test and it appears that the vaadin-upload uses file as the form data parameter name for the file. So in the line

file, handler, err := r.FormFile("uploadFile")

replace uploadFile with file and it should work.

It is documented on the vaadin homepage that

In order to support simultaneous uploads, instead of reusing the same FormData and XMLHttpRequest, we create a new one for each file. It is therefore alright for the server to only consider receiving one file per request.

However, I didn't see the parameter name (file) documented, so to be safe you should write your code so that it wouldn't use the name, ie something like

r.ParseMultipartForm(32 << 20)
m := r.MultipartForm
for _, v := range m.File {
    for _, f := range v {
        file, err := f.Open()
        if err != nil {
            fmt.Println(err)
            return
        }
        defer file.Close()
        // do something with the file data
        ...
    }
}



回答2:


Answering my own question for those who are facing same problem. Found out some code which can access file without knowing the key value.

func UploadHandler(res http.ResponseWriter, req *http.Request) {  
      var (  
           status int  
           err  error  
      )  
      defer func() {  
           if nil != err {  
                http.Error(res, err.Error(), status)  
           }  
      }()  
      // parse request  
     // const _24K = (1 << 20) * 24  
      if err = req.ParseMultipartForm(32 << 20); nil != err {  
           status = http.StatusInternalServerError  
           return  
      } 
        fmt.Println("No memory problem")
      for _, fheaders := range req.MultipartForm.File {  
           for _, hdr := range fheaders {  
                // open uploaded  
                var infile multipart.File  
                if infile, err = hdr.Open(); nil != err {  
                     status = http.StatusInternalServerError  
                     return  
                }  
                // open destination  
                var outfile *os.File  
                if outfile, err = os.Create("./uploaded/" + hdr.Filename); nil != err {  
                     status = http.StatusInternalServerError  
                     return  
                }  
                // 32K buffer copy  
                var written int64  
                if written, err = io.Copy(outfile, infile); nil != err {  
                     status = http.StatusInternalServerError  
                     return  
                }  
                res.Write([]byte("uploaded file:" + hdr.Filename + ";length:" + strconv.Itoa(int(written))))  
           }  
      }  
 } 



回答3:


Use exactly the same name for doing r.FormFile("selectedFile") that is there in your HTML tag. The key is mapped to input name used in your frontend HTML tag.

Below is my implementation:

<file
    type="file"
    name="selectedFile"
/>

const (
    S3_REGION = "Your region"
    S3_BUCKET = "Your Bucket Name"
)

func uploadFile(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Uploading File")
    r.ParseMultipartForm(32 << 20)

    file, handler, err := r.FormFile("selectedFile") // 
    if err != nil {
            fmt.Println("Error Retrieving the File")
            fmt.Println(err)
            return
    }

    defer file.Close()

    fmt.Printf("Uploaded File: %+v\n", handler.Filename)
    fmt.Printf("File Size: %+v\n", handler.Size)
    fmt.Printf("MIME Header: %+v\n", handler.Header)

    s, err := session.NewSession(&aws.Config{Region: aws.String(S3_REGION)})
    if err != nil {
        log.Fatal(err)
    }

    var size int64 = handler.Size
    buffer := make([]byte, size)
    file.Read(buffer)

    _, err = s3.New(s).PutObject(&s3.PutObjectInput{
        Bucket:               aws.String(S3_BUCKET),
        Key:                  aws.String(handler.Filename),
        ACL:                  aws.String("private"),
        Body:                 bytes.NewReader(buffer),
        ContentLength:        aws.Int64(size),
        ContentType:          aws.String(http.DetectContentType(buffer)),
        ContentDisposition:   aws.String("attachment"),
        ServerSideEncryption: aws.String("AES256"),
    })       
}


来源:https://stackoverflow.com/questions/39955057/not-able-to-save-uploaded-file-on-server-using-golang-and-polymer-http-no-such

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!