必须先调用 r.ParseForm()(或 r.ParseMultipartForm())再读取 r.Body;r.FormValue 同时查 URL 和 POST 数据,r.PostFormValue 仅查 POST 部分;ParseMultipartForm 的 maxMemory 不可设为 0,否则导致 OOM。

Go 的 ParseForm 必须在读取请求体前调用
很多新手会先调用 r.Body.Read 或用 io.ReadAll(r.Body) 拿到原始数据,再试图调用 r.ParseForm() —— 这会导致 r.Form 为空或报错 http: request body too large。因为 ParseForm 内部会尝试读取并解析 body,而 Body 是单次可读的流,一旦被提前消费,后续解析就失效。
正确顺序只有一条:必须在任何读取 r.Body 之前,先调用 r.ParseForm()(或 r.ParseMultipartForm())。
- GET 请求:
r.ParseForm()解析 URL 查询参数到r.Form和r.PostForm - POST 表单(
application/x-www-form-urlencoded):同样走ParseForm() - POST 文件上传(
multipart/form-data):必须用r.ParseMultipartForm(maxMemory),否则r.FormValue可能拿不到字段值
r.FormValue 和 r.PostFormValue 的区别在哪
r.FormValue(key) 会同时查找 URL 查询参数(GET)和 POST 表单字段(包括 multipart),是开发中最常用的取值方式;r.PostFormValue(key) 则只查 POST 部分(即 r.PostForm),对 GET 请求返回空字符串。
典型误用场景:用 r.PostFormValue 处理一个既支持 GET 又支持 POST 的搜索接口,结果 GET 请求永远拿不到值。
立即学习“go语言免费学习笔记(深入)”;
- 统一用
r.FormValue("name")覆盖两种提交方式 - 若需严格区分来源(比如审计日志),再分别查
r.URL.Query().Get("name")和r.PostFormValue("name") -
r.FormValue在未调用ParseForm前返回空,不会 panic,但容易掩盖逻辑错误
处理 multipart 表单时忘记设置 maxMemory 会卡住
调用 r.ParseMultipartForm(0) 看似“不限制内存”,实际会让 Go 把整个文件内容缓存进内存 —— 上传一个 500MB 视频就直接 OOM。而设为 32 (32MB)后,超出部分会自动写入临时磁盘文件,r.MultipartForm.File 和 r.MultipartForm.Value 仍可正常访问。
PHP经典实例(第2版)能够为您节省宝贵的Web开发时间。有了这些针对真实问题的解决方案放在手边,大多数编程难题都会迎刃而解。《PHP经典实例(第2版)》将PHP的特性与经典实例丛书的独特形式组合到一起,足以帮您成功地构建跨浏览器的Web应用程序。在这个修订版中,您可以更加方便地找到各种编程问题的解决方案,《PHP经典实例(第2版)》中内容涵盖了:表单处理;Session管理;数据库交互;使用We
注意:r.ParseMultipartForm 不是可选步骤。即使你只想要表单字段、不关心文件,只要 Content-Type 是 multipart/form-data,就必须调用它,否则 r.FormValue 对所有字段都返回空。
- 推荐起始值:
r.ParseMultipartForm(32 - 临时文件路径由
os.TempDir()决定,可通过os.Setenv("TMPDIR", "/path")调整 - 解析后记得用
defer r.MultipartForm.RemoveAll()清理临时文件(尤其在长连接或中间件中)
中文表单值乱码?检查客户端 Content-Type 声明
Go 的 net/http 默认按 UTF-8 解析表单,但前提是客户端明确声明了编码。如果前端 HTML 表单没写 accept-charset="UTF-8",或某些旧浏览器/工具(如 curl)未设 -H "Content-Type: application/x-www-form-urlencoded; charset=utf-8",Go 仍会尝试解析,但可能把字节序列当 Latin-1 处理,导致中文变问号或乱码。
服务端无法强制修正客户端编码声明,只能防御性处理:
- 确保前端 form 标签含
accept-charset="UTF-8" - API 文档要求客户端显式设置
Content-Typeheader - 必要时手动解码:
url.PathUnescape(r.FormValue("text"))(仅当确认是 double-encoded 时)
真正棘手的是那些绕过标准表单、用 fetch 手动拼接 query string 的前端代码——它们很容易漏掉 encodeURIComponent,导致空格、中文等字符未编码,服务端收到的就是损坏的字节流。









