需先调用 r.ParseForm() 或 r.ParseMultipartForm() 才能获取表单值,否则 r.FormValue 始终为空;GET 用 r.URL.Query().Get,POST 必 parse 后取值;验证须手写,检查存在性、非空性、格式合法性,并 trim 空格;重定向传错用 session 或加密 cookie,且需回填合法字段。
如何用 http.HandleFunc 接收表单数据
Go 的标准库不自动解析表单,必须显式调用 r.ParseForm() 或 r.ParseMultipartForm(),否则 r.FormValue("key") 总是空字符串。
常见错误是直接读 r.FormValue 却忘了 parse —— 这会导致所有字段都取不到值,且无报错。
- GET 表单:用
r.URL.Query().Get("name")更轻量,无需 parse - POST 表单(
application/x-www-form-urlencoded):必须先r.ParseForm(),再用r.FormValue("email") - 含文件上传的 POST(
multipart/form-data):必须用r.ParseMultipartForm(32 ,参数是最大内存缓存字节数,太小会触发磁盘临时文件,太大可能 OOM
ParseForm 失败时为什么没报错但数据为空
r.ParseForm() 内部忽略多数解析错误(比如 malformed body),只记录在 r.ParseError 字段里,而这个字段默认不暴露、也不 panic。你得主动检查:
if err := r.ParseForm(); err != nil {
http.Error(w, "invalid form", http.StatusBadRequest)
return
}
更隐蔽的问题是:如果前端发了 JSON 但 Content-Type 写成 application/x-www-form-urlencoded,ParseForm() 会静默失败(因为无法解析 JSON 字符串为键值对),此时 r.Form 为空 map。
- 务必校验
r.Header.Get("Content-Type")是否匹配预期类型 - 调试时可打印
r.Body前 200 字节(用io.LimitReader防止读爆)看原始请求体 - 不要依赖
len(r.Form) > 0判断提交成功 —— 它可能因 parse 失败而为空
手动验证表单字段的最小可靠模式
Go 没有内置验证器,别依赖 struct tag + 第三方库做“全自动”校验 —— 很多库对空字符串、零值、缺失字段的处理逻辑不一致,反而掩盖业务语义。