英文:
Getting Content-Type header for uploaded files processed using net/http request.ParseMultipartForm
问题
我正在使用net/http包编写一个服务器,其中包括通过POST上传的使用multipart/form-data编码的文件。
在阅读net/http文档时,我已经成功编写了一个函数,该函数在请求上调用ParseMultipartForm方法,然后查询MultipartForm字段以获取文件数据,但是我似乎无法获取作为POST请求的一部分上传的各个文件的内容类型--请求源代码中与ContentType相关的引用似乎都与获取multipart/form编码有关,当我使用printf-dump打印上传的文件信息时,似乎没有看到任何与内容类型相关的类型、字段或映射键。
以下是我目前正在处理文件上传的代码:
func save_multipart_upload(r *http.Request, savepath string) ([]string, error) {
fmt.Println("CALL: save_multipart_upload(r," + savepath + ")")
var savedfiles []string
err := r.ParseMultipartForm(100000)
if err != nil {
return savedfiles, err
}
m := r.MultipartForm
fmt.Printf("MPF: %#v \n", m)
for fname, _ := range r.MultipartForm.File {
files := m.File[fname]
fmt.Printf("files: %#v \n", m)
for i, _ := range files {
//for each fileheader, get a handle to the actual file
file, err := files[i].Open()
fmt.Printf("file: %#v \n", file)
defer file.Close()
if err != nil {
return savedfiles, err
}
//create destination file making sure the path is writeable.
var filename string
if savepath[:len(savepath)] == "/" {
filename = savepath + files[i].Filename
} else {
filename = savepath + "/" + files[i].Filename
}
dst, err := os.Create(filename)
if err != nil {
fmt.Println("Can't create " + filename + ": " + err.Error())
return savedfiles, err
} else if _, err := io.Copy(dst, file); err != nil {
fmt.Println("Can't copy data %s: " + err.Error(), filename)
return savedfiles, err
} else {
fmt.Println("Saved %s successfully.", filename)
savedfiles = append(savedfiles, files[i].Filename)
}
}
}
/* end multipart upload */
fmt.Println("RETURN: receive_multipart_upload")
return savedfiles, err
}
如果我选择一个视频文件,以下是我从打印输出中看到的内容:
CALL: save_multipart_upload(r,./static/000000000000000000000000/video/)
MPF: &multipart.Form{Value:map[string][]string{}, File:map[string][]*multipart.FileHeader{"file1":[]*multipart.FileHeader{(*multipart.FileHeader)(0xc21004e580)}}}
files: &multipart.Form{Value:map[string][]string{}, File:map[string][]*multipart.FileHeader{"file1":[]*multipart.FileHeader{(*multipart.FileHeader)(0xc21004e580)}}}
file: &os.File{file:(*os.file)(0xc210079510)}
Saved %s successfully. ./static/000000000000000000000000/video//2012-08-03 19.31.48.mov
RETURN: receive_multipart_upload
multipart.FileHeader看起来可能是一个线索,但是当我深入查看时,它有一个Header字段,该字段的类型为textproto.MIMEHeader,它基本上看起来是一个字符串到字符串的映射,所以我仍然不知道要查找什么。
如果你有任何想法、示例代码或对我现有代码的建议修改,我将不胜感激!
英文:
I'm using the net/http package to write a server that, among other things, receives a files uploaded via POST with the multipart/form-data encoding.
Working my way through the net/http docs, I've managed to write a function that calls the ParseMultipartForm method on the request and then interrogates the MultipartForm field for the file data, but I seem to be stuck on how to get the Content Type of the individual files uploaded as part of the post request -- all the ContentType related references in the source of request.go seem to be related to getting the multipart/form encoding, and when I printf-dump the uploaded file information, I don't seem to see any types, fields, or map keys that look content type related.
Here's what I've got right now that's doing the work of the file upload:
func save_multipart_upload(r *http.Request, savepath string) ([]string, error) {
fmt.Println("CALL: save_multipart_upload(r,"+savepath+")")
var savedfiles []string
err := r.ParseMultipartForm(100000)
if err != nil {
return savedfiles, err
}
m := r.MultipartForm
fmt.Printf("MPF: %#v \n", m)
for fname, _ := range r.MultipartForm.File {
files := m.File[fname]
fmt.Printf("files: %#v \n", m)
for i, _ := range files {
//for each fileheader, get a handle to the actual file
file, err := files[i].Open()
fmt.Printf("file: %#v \n", file)
defer file.Close()
if err != nil {
return savedfiles, err
}
//create destination file making sure the path is writeable.
var filename string
if savepath[:len(savepath)] == "/" {
filename = savepath + files[i].Filename
} else {
filename = savepath + "/" + files[i].Filename
}
dst, err := os.Create(filename)
if err != nil {
fmt.Println("Can't create "+filename+": "+err.Error())
return savedfiles, err
} else if _, err := io.Copy(dst, file); err != nil {
fmt.Println("Can't copy data %s: "+err.Error(), filename)
return savedfiles, err
} else {
fmt.Println("Saved %s successfully.", filename)
savedfiles = append(savedfiles, files[i].Filename)
}
}
}
/* end multipart upload */
fmt.Println("RETURN: receive_multipart_upload")
return savedfiles, err
}
And here's what I see from the print dumping if I pick a video file:
>CALL: save_multipart_upload(r,./static/000000000000000000000000/video/)
>
>MPF: &multipart.Form{Value:map[string][]string{}, File:map[string][]*multipart.FileHeader{"file1":[]*multipart.FileHeader{(*multipart.FileHeader)(0xc21004e580)}}}
>
>files: &multipart.Form{Value:map[string][]string{}, File:map[string][]*multipart.FileHeader{"file1":[]*multipart.FileHeader{(*multipart.FileHeader)(0xc21004e580)}}}
>
>file: &os.File{file:(*os.file)(0xc210079510)}
>
>Saved %s successfully. ./static/000000000000000000000000/video//2012-08-03 19.31.48.mov
>
>RETURN: receive_multipart_upload
multipart.FileHeader looks like it might be a clue, but when I drill down, that has a Header field, which is of type textproto.MIMEHeader, which basically looks like it's a map of strings to strings, so I still don't know what to look for.
Any ideas and sample code or suggested alterations to what I've got would be appreciated!
答案1
得分: 3
这是代码的中文翻译:
m := r.MultipartForm
header := m.MIMEHeader
// 查看例如 https://en.wikipedia.org/wiki/MIME#Multipart_messages
// 你需要查找 Content-Type...
// 但是,它可以有多个值。这就是为什么你得到一个切片。
types, ok := header["Content-Type"]
if ok {
// 这应该是真的!
for _, x := range types {
fmt.Printf("Content-Type: %v", x)
// 大多数情况下,你可能只会看到一个
}
}
请注意,这只是代码的翻译部分,不包括任何其他内容。
英文:
It should work like this:
m := r.MultipartForm
header := m.MIMEHeader
// Take a look at for instance
// https://en.wikipedia.org/wiki/MIME#Multipart_messages
// You are looking for Content-Type...
// However, it can be multivalued. That's why you get a splice.
types, ok := header["Content-Type"]
if ok {
// This should be true!
for _, x := range types {
fmt.Printf("Content-Type: %v", x)
// Most usually you will probably see only one
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论