必须用parsemultipartform处理multipart/form-data请求,即使只含文本字段;parseform仅适用于application/x-www-form-urlencoded,对multipart完全无效,不调用parsemultipartform则r.formvalue等均返回空。

Go中用ParseForm还是ParseMultipartForm?
表单数据是否含文件上传,直接决定该用哪个解析函数。如果只处理普通字段(如username、age),ParseForm足够且更轻量;一旦请求头是multipart/form-data(哪怕只是带了个空文件输入框),就必须先调ParseMultipartForm,否则r.FormValue取不到值。
常见错误是没检查Content-Type就硬调ParseForm,结果在Postman里传了文件字段却始终返回空字符串。实际做法应是:
- 先调
r.ParseMultipartForm(32 (32MB内存上限,避免OOM) - 若报错
http.ErrNotMultipart,再退回到r.ParseForm() - 统一用
r.PostFormValue取值(它兼容两种解析后的状态)
Query和PostForm取值行为差异
URL查询参数(?id=123&name=foo)走r.URL.Query(),而POST/PUT的body参数走r.PostFormValue。两者不互通——即使同名参数同时存在,r.FormValue默认只返回PostForm里的值,忽略Query。
这容易导致调试时误判:比如前端把token放query、业务参数放body,后端只用r.FormValue("token")就拿不到,必须显式写r.URL.Query().Get("token")。
- 需要合并查询与表单参数时,手动遍历
r.URL.Query()和r.PostForm并合并到一个map[string][]string -
r.FormValue本质是r.PostFormValue的别名,不是“自动混合” - GET请求没有body,
r.PostForm为空;POST请求的query参数仍可读,但不会进r.PostForm
字符串转数字时panic的三个典型场景
Go标准库不提供“安全转换”,strconv.Atoi(r.FormValue("id"))遇到空字符串或非数字会返回error,但很多人直接忽略err,导致后续逻辑用0当ID出错;更危险的是用MustXXX类函数(如某些第三方库),一错就panic。
- 空值:
r.FormValue("page")返回空字符串,strconv.Atoi("")返回0, "strconv.Atoi: parsing \"\": invalid syntax" - 溢出:
strconv.ParseInt("99999999999999999999", 10, 64)可能返回math.MaxInt64而非报错(取决于实现) - 负号缺失:
uint类型转换时,若传入负数字符串,strconv.ParseUint会报strconv.ParseUint: parsing "-1": invalid syntax,但错误信息没提类型,容易误以为是格式问题
建议封装一层:func ParseIntParam(r *http.Request, key string, def int64) (int64, error),内部先TrimSpace,再判断空,最后选合适函数。
结构体绑定时忽略未知字段和零值
用json.Unmarshal或schema类库做绑定时,前端多传个__v字段或少传email,会导致校验失败或字段被置零。原生encoding/json默认不忽略未知字段,且""、0、false会被反序列化为对应类型的零值,掩盖真实缺失。
- 加
json:",omitempty"标签可跳过零值字段输出,但不影响输入解析 - 要忽略未知字段,得用
json.Decoder并设置DisallowUnknownFields() - 真正可控的方式是先用
map[string]interface{}解一次,校验键名是否存在、类型是否匹配,再赋值给结构体
最常被忽略的是时间字段:time.Time零值是0001-01-01,前端传"2024-01-01"但结构体没设time.RFC3339标签,就会解析失败或变成零时间——必须显式指定json:"created_at,string"并配UnmarshalJSON方法。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











