r.ParseForm()
具体原因很简单,看下面这个示例代码就知道了:
Bug 重现
package main
import (
"net/http"
)
func HelloServer1(w http.ResponseWriter, r *http.Request) {
//r.ParseForm()
val := r.FormValue("key")
println("HelloServer1", val)
w.Write([]byte(val))
}
func HelloServer2(w http.ResponseWriter, r *http.Request) {
//r.ParseForm()
_, fe := r.MultipartReader()
if fe != nil {
println("HelloServer2", fe)
return
}
val := r.FormValue("key")
println("HelloServer2", val)
w.Write([]byte(val))
}
func HelloServer3(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
_, fe := r.MultipartReader()
if fe != nil {
println("HelloServer3", fe)
return
}
val := r.FormValue("key")
println("HelloServer3", val)
w.Write([]byte(val))
}
func main() {
http.HandleFunc("/hello1", HelloServer1)
http.HandleFunc("/hello2", HelloServer2)
http.HandleFunc("/hello3", HelloServer3)
println("start ...")
err := http.ListenAndServe(":8888", nil)
if err != nil {
println("error", err)
}
}
三次POST请求的结果分别如下:
- 返回结果正确
curl -F "name=yanyiwu" "localhost:8888/hello1?key=value1"
value1
虽然在调用 r.FormValue 之前没有调用过 r.ParseForm , 但是返回的结果正确。 因为在 r.FormValue 函数之内当 r.Form == nil 时会先调用 ParseMultipartForm 。
- 返回结果错误
curl -F "name=yanyiwu" "localhost:8888/hello2?key=value2"
http: multipart handled by MultipartReadergolang/go/src/net/http/request.go
- 返回结果正确
curl -F "name=yanyiwu" "localhost:8888/hello3?key=value3"
value3
r.ParseForm()
解决方案
在调用 r.FormValue 之前记得 r.ParseForm 即可。
go 的 net/http 源码还可以更完善一点
其实我个人看来,go源码里面 r.FormValue 函数里面调用 ParseMultipartForm 的时候,没有检查 ParseMultipartForm 的返回值 是不太完善的做法。 个人觉得应该检查返回值,虽然无法将错误返回(因为 r.FormValue 的返回值只有一个,是 string 类型), 但是可以将错误打印出来,以此提醒开发者。
pull request