c.FormValue 获取的字符串必须手动清洗和校验,因其保留空格、控制字符且不处理未勾选字段;混合表单需先调 c.MultipartForm();清洗须在验证前统一处理。

直接用 c.FormValue 取值就行,但必须清楚它不自动清洗、不校验、不处理空格和控制字符——这些全得你手动补。
为什么 c.FormValue 拿到的字符串不能直接用
它只是解码后的原始输入:前后空格保留、零宽字符(如 \u200B)照单全收、" " 和 "" 都返回空字符串、未勾选的 checkbox 根本不出现。前端传 email=%20admin%40example.com%20,后端拿到的就是带空格的邮箱;用户粘贴进来的文本可能含 \u00AD(软连字符),导致后续 == 判断静默失败。
- 所有字符串字段都应先过
strings.TrimSpace() - 高危 Unicode 字符需硬过滤:
\u00AD、\u200B-\u200D、\uFEFF、\u2060、\u202E - 邮箱、数字、布尔等类型字段不能跳过转换和 error 检查——
strconv.Atoi(c.FormValue("age"))对空字符串返回0, error,直接用 0 就是逻辑漏洞
c.MultipartForm() 必须在混合上传时显式调用
表单同时含文件和文本字段(比如头像上传 + 用户名 + 简介),只靠 c.FormValue 会漏掉所有字段——Fiber 不会在你调 c.FormValue 时自动触发 multipart 解析。必须先执行 c.MultipartForm(),否则 c.FormValue 返回空,c.File 也拿不到文件。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 调用
c.MultipartForm()后,普通字段仍可用c.FormValue读取(框架内部已解析) - 但若想统一处理所有字段(尤其要做批量清洗),建议直接从
form.Value(map[string][]string)里取,避免重复调用 - 注意
c.MultipartForm()默认内存限制是 32MB;若上传大文件且没配c.App().Config().BodyLimit,可能被截断或返回 error
数据清洗别堆在 handler 里写三行 TrimSpace 就完事
清洗逻辑分散在每个字段处理处,既难复用又容易漏。推荐把清洗函数抽象成统一入口,例如:
func cleanString(s string) string {
s = strings.TrimSpace(s)
return strings.Map(func(r rune) rune {
if unicode.IsControl(r) && !unicode.IsSpace(r) ||
r == '\u00AD' || r == '\uFEFF' || r == '\u2060' || r == '\u202E' {
return -1
}
return r
}, s)
}
- 邮箱字段再套一层
strings.ToLower(cleanString(raw)) - 富文本字段走
bluemonday.UGCPolicy().Sanitize(),不是正则替换 - 纯文本需求(如日志、短信)别用 HTML 清洗库,改用
goquery.NewDocumentFromReader提取 text 节点
最易被忽略的是:清洗必须在验证之前完成。如果先用 validator.Struct() 校验,再 trim 空格,那 validate:"required" 就会把 " " 当作非空通过——结构体字段还没被清洗,校验就结束了。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










