英文:
Go http server handle POST data difference?
问题
我有一个简单的上传表单,如下所示:
<html>
<title>Go upload</title>
<body>
<form action="http://localhost:8899/up" method="post" enctype="multipart/form-data">
<label for="file">文件路径:</label>
<input type="text" name="filepath" id="filepath">
<p>
<label for="file">内容:</label>
<textarea name="jscontent" id="jscontent" style="width:500px;height:100px" rows="10" cols="80"></textarea>
<p>
<input type="submit" name="submit" value="提交">
</form>
</body>
</html>
服务器端代码如下:
package main
import (
"net/http"
"log"
)
func defaultHandler(w http.ResponseWriter, r *http.Request) {
log.Println(r.PostFormValue("filepath"))
}
func main() {
http.HandleFunc("/up", defaultHandler)
http.ListenAndServe(":8899", nil)
}
问题是当我使用 enctype="multipart/form-data"
时,我无法通过 r.PostFormValue
从客户端获取值,但如果我将其设置为 enctype="application/x-www-form-urlencoded"
,Go文档中说:
PostFormValue返回POST或PUT请求体中命名组件的第一个值。URL查询参数将被忽略。
如果需要,PostFormValue会调用ParseMultipartForm和ParseForm,并忽略这些函数返回的任何错误。
那么为什么他们在这里没有提到 enctype
呢?
英文:
I have a simple upload form as
<html>
<title>Go upload</title>
<body>
<form action="http://localhost:8899/up" method="post" enctype="multipart/form-data">
<label for="file">File Path:</label>
<input type="text" name="filepath" id="filepath">
<p>
<label for="file">Content:</label>
<textarea name="jscontent" id="jscontent" style="width:500px;height:100px" rows="10" cols="80"></textarea>
<p>
<input type="submit" name="submit" value="Submit">
</form>
</body>
</html>
And server side
package main
import (
"net/http"
"log"
)
func defaultHandler(w http.ResponseWriter, r *http.Request) {
log.Println(r.PostFormValue("filepath"))
}
func main() {
http.HandleFunc("/up", defaultHandler)
http.ListenAndServe(":8899", nil)
}
The problem is when I use enctype="multipart/form-data"
, I cannot get the value from client with r.PostFormValue
, but it's ok if I set to enctype="application/x-www-form-urlencoded"
, go document say
> PostFormValue returns the first value for the named component of the POST
> or PUT request body. URL query parameters are ignored.
> PostFormValue calls ParseMultipartForm and ParseForm if necessary and ignores
> any errors returned by these functions.
So why they did not say anything about enctype
here ?
答案1
得分: 1
如果你使用"multiplart/form-data"
作为表单数据的编码类型,你需要使用Request.FormValue()
函数来读取表单的值(注意不是PostFormValue
)。
将你的defaultHandler()
函数修改为:
func defaultHandler(w http.ResponseWriter, r *http.Request) {
log.Println(r.FormValue("filepath"))
}
这样就可以正常工作了。原因是因为Request.FormValue()
和Request.PostFormValue()
在需要时(如果表单编码类型是multipart
且尚未解析)都会首先调用Request.ParseMultipartForm()
,而Request.ParseMultipartForm()
只会将解析后的表单键值对存储在Request.Form
中,而不是Request.PostForm
中:Request.ParseMultipartForm()源代码
。
这可能是一个bug,但即使这是预期的工作方式,文档中也应该提到。
英文:
If you use "multiplart/form-data"
form-data encoding type you have to read form values with the Request.FormValue()
function (note that not PostFormValue
!).
Change your defaultHandler()
function to:
func defaultHandler(w http.ResponseWriter, r *http.Request) {
log.Println(r.FormValue("filepath"))
}
And it will work. The reason for this is because both Request.FormValue()
and Request.PostFormValue()
first call Request.ParseMultipartForm()
if needed (if form encodying type is multipart
and it has not yet been parsed) and Request.ParseMultipartForm()
only stores the parsed form name-value pairs in the Request.Form
and not in Request.PostForm
: Request.ParseMultipartForm() source code
This may well be a bug, but even if this is the intended working, it should be mentioned in the documentation.
答案2
得分: 0
如果您想上传文件,您需要使用 multipart/form-data
编码类型,输入字段必须是 type=file
,并使用 FormFile
方法而不是 PostFormValue
方法(后者只返回一个字符串)。
<html>
<title>Go upload</title>
<body>
<form action="http://localhost:8899/up" method="post" enctype="multipart/form-data">
<label for="filepath">File Path:</label>
<input type="file" name="filepath" id="filepath">
<p>
<label for="jscontent">Content:</label>
<textarea name="jscontent" id="jscontent" style="width:500px;height:100px" rows="10" cols="80"></textarea>
<p>
<input type="submit" name="submit" value="Submit">
</form>
</body>
</html>
package main
import (
"log"
"net/http"
)
func defaultHandler(w http.ResponseWriter, r *http.Request) {
file, header, err := r.FormFile("filepath")
defer file.Close()
if err != nil {
log.Println(err.Error())
}
log.Println(header.Filename)
// 将文件复制到文件夹或其他位置
}
func main() {
http.HandleFunc("/up", defaultHandler)
http.ListenAndServe(":8899", nil)
}
英文:
If you are trying to upload files you need to use the multipart/form-data
enctype, the input field must be type=file
and use the FormFile
instead of PostFormValue
(that returns just a String) method.
<html>
<title>Go upload</title>
<body>
<form action="http://localhost:8899/up" method="post" enctype="multipart/form-data">
<label for="filepath">File Path:</label>
<input type="file" name="filepath" id="filepath">
<p>
<label for="jscontent">Content:</label>
<textarea name="jscontent" id="jscontent" style="width:500px;height:100px" rows="10" cols="80"></textarea>
<p>
<input type="submit" name="submit" value="Submit">
</form>
</body>
</html>
<!-- -->
package main
import (
"log"
"net/http"
)
func defaultHandler(w http.ResponseWriter, r *http.Request) {
file, header, err := r.FormFile("filepath")
defer file.Close()
if err != nil {
log.Println(err.Error())
}
log.Println(header.Filename)
// Copy file to a folder or something
}
func main() {
http.HandleFunc("/up", defaultHandler)
http.ListenAndServe(":8899", nil)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论