
在 Go 的 HTTP 处理函数中,可通过为多个 元素统一设置 name 属性,并使用 r.FormValue("name") 获取用户点击的提交按钮值,无需 AJAX 或隐藏字段。
在 go 的 http 处理函数中,可通过为多个 `
在构建多操作表单(例如“保存”、“草稿”、“删除”等不同语义的提交行为)时,常需区分用户点击的是哪个提交按钮。HTML 标准规定:只有带有 name 属性的 ;若省略 name,该按钮的值将不会出现在请求表单数据中。
因此,关键修复在于为按钮添加 name 属性——与普通 一致,name 是服务端识别字段的唯一标识符。
✅ 正确的 HTML 写法如下:
<form action="/save" method="POST">
<div>
<span>Title: </span>
<textarea name="title" placeholder="Link">{{printf "%s" .Title}}</textarea>
</div>
<div>
<button type="submit" name="action" value="save">保存</button>
<button type="submit" name="action" value="draft">存为草稿</button>
<button type="submit" name="action" value="cancel">取消</button>
</div>
</form>注意:所有按钮共享相同的 name="action",但 value 各不相同。这样,无论用户点击哪一个,请求体中都会包含形如 action=save 的键值对。
对应的 Go 处理函数可直接使用标准库方法提取:
func saveHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// 解析表单(自动调用 ParseForm,支持 application/x-www-form-urlencoded 和 multipart/form-data)
if err := r.ParseForm(); err != nil {
http.Error(w, "Failed to parse form", http.StatusBadRequest)
return
}
title := r.FormValue("title")
action := r.FormValue("action") // ✅ 获取点击的按钮值
switch action {
case "save":
// 执行完整保存逻辑
log.Printf("Saving title: %s", title)
case "draft":
// 执行草稿保存逻辑
log.Printf("Saving as draft: %s", title)
case "cancel":
// 重定向或清理操作
http.Redirect(w, r, "/", http.StatusSeeOther)
return
default:
http.Error(w, "Unknown action", http.StatusBadRequest)
return
}
// 响应成功
w.Header().Set("Content-Type", "text/plain")
fmt.Fprintf(w, "Success: %s with title '%s'", action, title)
}⚠️ 注意事项:
- r.FormValue() 内部会自动调用 r.ParseForm()(若尚未解析),但在生产环境建议显式调用 r.ParseForm() 并检查错误,以获得更精确的错误控制;
- 若表单含文件上传(),必须使用 r.ParseMultipartForm(),且 r.FormValue() 仍可安全读取普通文本字段;
- 避免仅依赖按钮 id 或 class 判断操作——它们不会随请求发送,服务端完全不可见;
- 不推荐使用 JavaScript 拦截表单 + 隐藏字段模拟,既增加复杂度,又破坏语义化和无障碍访问(a11y)。
总结:Go 中识别多按钮提交的核心原则是——让浏览器按规范提交,让服务端按标准接收。只需确保每个










