我正在使用vaadin上传来上传带有聚合物的Web应用程序上的文件。我正在使用golang作为后端。
<vaadin-upload target="../upload" max-files="20" accept="application/pdf,image/*"
method="POST"> </vaadin-upload>
我检查了vaadin上传中使用的编码类型是 multipart / form-data 。 我的golang代码如下。
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)
}
}
它在服务器端出现错误 http:没有这样的文件。我检查了当提供的文件字段名称不在请求中或文件字段中时,FormFile返回此错误。
答案 0 :(得分:2)
进行了快速测试,看来vaadin-upload
使用file
作为文件的表单数据参数名称。所以在行
file, handler, err := r.FormFile("uploadFile")
将uploadFile
替换为file
,它应该有效。
documented on the vaadin homepage
为了支持同步上传,我们不是重复使用相同的FormData和XMLHttpRequest,而是为每个文件创建一个新的。因此,服务器只考虑每个请求接收一个文件。
但是,我没有看到记录的参数名称(file
),所以为了安全起见,您应该编写代码,以便它不会使用该名称,例如
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
...
}
}
答案 1 :(得分:1)
为那些面临同样问题的人回答我自己的问题。找到一些可以在不知道键值的情况下访问文件的代码。
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))))
}
}
}
答案 2 :(得分:0)
使用与HTML标记中存在的r.FormFile(“ selectedFile”)完全相同的名称。密钥映射到前端HTML标记中使用的输入名称。
以下是我的实现:
<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"),
})
}