html表单原生仅支持get/post,method="delete"会被浏览器强制转为post,导致buffalo路由匹配失败而返回405;须用fetch或_method隐藏字段+methodoverride中间件实现delete,并注意csrf token校验。

Buffalo 默认不自动处理 DELETE 请求的表单提交,因为浏览器原生表单只支持 GET 和 POST —— 你看到的 405 Method Not Allowed 或路由 404,大概率是这个原因。
为什么 form 提交 DELETE 会失败
HTML 表单的 method 属性只认 "GET" 和 "POST";即使你写成 method="DELETE",浏览器仍会发 POST 请求。Buffalo 的路由匹配严格按 HTTP 方法区分,所以 DELETE /users/123 路由根本收不到这个请求。
- 浏览器控制台可能显示:Failed to load resource: the server responded with a status of 405 (Method Not Allowed)
-
buffalo dev日志里会出现类似POST /users/123 not found的提示,而不是DELETE相关日志 - 用
curl -X DELETE http://localhost:3000/users/123测试能通,说明路由本身没问题
正确注册 DELETE 路由并绑定 handler
在 app.go 中用 app.Delete() 显式声明,不能依赖隐式生成(比如 buffalo generate resource 会帮你加,但手动写时容易漏):
Buffalo框架 1.0.1 版本源码包下载,适合需要错误处理改进、依赖更新、render.Download 注释和 request logger 调整的 v1 项目。
app.Delete("/users/{id}", actions.UsersDestroy)
对应 handler 示例(注意必须返回 error):
func UsersDestroy(c buffalo.Context) error {
id := c.Param("id")
user := &models.User{}
if err := models.DB.Find(user, id); err != nil {
return c.Error(404, err)
}
if err := models.DB.Destroy(user); err != nil {
return c.Error(500, err)
}
return c.Render(200, r.JSON(map[string]string{"success": "deleted"}))
}
- 参数名必须和路由中
{id}一致,c.Param("id")才能取到 - 别忘了在 handler 上方 import
"github.com/gobuffalo/buffalo-pop/v2/pop"(如果用了 pop) - 返回
c.Render()或c.Redirect(),不能只写return nil,否则 Buffalo 会 panic
前端如何安全触发 DELETE
两种可靠方式,避免伪造 method 属性:
- 用 JavaScript 发起 fetch:
fetch(`/users/${id}`, { method: "DELETE" }) .then(r => r.json()) .then(console.log); - 用隐藏字段 + middleware 模拟(兼容老浏览器):
表单保持method="POST",加一个隐藏字段<input name="_method" value="DELETE">,再在app.go开启app.Use(middleware.MethodOverride)—— Buffalo 内置支持该中间件,会把带_method=DELETE的 POST 自动转为 DELETE
容易被忽略的点
CSRF 保护默认开启,而 DELETE 请求若走表单提交(哪怕用了 _method),必须带上 authenticity_token 字段,否则 422 Unprocessable Entity;但 fetch 方式不受影响,因为它不走表单提交流程。如果你在表单里删数据,记得从 context 里传 token 到模板:
<input name="authenticity_token" value="${context.Get(" authenticity_token>否则删操作永远卡在 CSRF 校验。










