Buffalo 默认不限制请求体大小,需用 http.MaxBytesReader 在中间件中硬限制,并置于 session 等中间件之前;multipart 场景还需显式调用 ParseMultipartForm 并设 maxMemory。

Buffalo 默认不限制请求体大小,但实际运行时会受底层 HTTP 服务器(如 net/http)默认限制影响——Go 标准库的 http.Server.MaxRequestBodySize 在 Go 1.19+ 才支持,而 Buffalo 未封装该配置,直接设为 0(即无上限),极易引发内存耗尽或 DoS 风险。
为什么不能直接用 buffalo.Context.Request().Body 读取后校验?
Buffalo 的中间件链在 request.Body 被读取前就可能触发模板渲染、session 解析等操作;一旦 Body 被提前消费(例如调用 c.Request().Body 后未重置),后续中间件或 handler 会读到空数据,导致 c.Param()、c.Form()、c.MultipartForm() 全部失效。
- 不是“忘了读”,而是读了就没了——HTTP body 是单次流式读取
- Buffalo 的
c.Request()返回的是原始*http.Request,但它的生命周期和中间件顺序强耦合 - 你手动
io.Copy(ioutil.Discard, r.Body)后,c.FormValue("name")就返回空字符串
正确做法:在中间件里用 http.MaxBytesReader 包裹 Body
必须在所有依赖 Body 的中间件(如 session、form parser)之前插入自定义中间件,用 http.MaxBytesReader 做硬限制。Buffalo 不提供开箱即用的配置项,得自己写:
Buffalo框架 1.0.1 版本源码包下载,适合需要错误处理改进、依赖更新、render.Download 注释和 request logger 调整的 v1 项目。
func MaxBodySizeMiddleware(max int64) buffalo.MiddlewareFunc {
return func(next buffalo.Handler) buffalo.Handler {
return func(c buffalo.Context) error {
r := c.Request()
r.Body = http.MaxBytesReader(c.Response(), r.Body, max)
return next(c)
}
}
}
- 放在
app.Use()最前面,比如app.Use(MaxBodySizeMiddleware(5 * 1024 * 1024))限制 5MB - 注意:这个中间件必须在
session.Middleware和buffalo.PopTransaction之前,否则它们会先读 Body - 触发超限时,
http.MaxBytesReader会返回http.ErrBodyTooLarge,Buffalo 默认返回 400,无需额外处理
上传文件场景要额外处理 multipart/form-data
单纯限制 Request.Body 对 multipart 无效——Go 的 ParseMultipartForm 会把文件临时写入磁盘或内存,不受 MaxBytesReader 约束。必须显式调用 r.ParseMultipartForm(maxMemory) 并捕获错误:
func UploadHandler(c buffalo.Context) error {
r := c.Request()
// 先解析 multipart,限定内存使用(单位字节)
if err := r.ParseMultipartForm(32 << 20); err != nil {
if errors.Is(err, http.ErrMissingBoundary) || errors.Is(err, http.ErrNotMultipart) {
return c.Error(http.StatusBadRequest, err)
}
if errors.Is(err, http.ErrMessageTooLarge) {
return c.Error(http.StatusRequestEntityTooLarge, err)
}
return c.Error(http.StatusInternalServerError, err)
}
// 后续处理 c.Request().MultipartForm
return c.Render(200, r.JSON(map[string]string{"ok": "uploaded"}))
}
32 表示 32MB 内存缓冲,超出部分写临时文件;这个值要和 <code>MaxBytesReader的上限一致-
http.ErrMessageTooLarge是 Go 1.19+ 引入的明确错误类型,旧版本需检查err.Error()是否含 "message too large" - 别依赖
c.File()或c.Param()——它们内部会自动调用ParseMultipartForm,但不传参,用的是默认 32MB,且错误处理不透明
真正难搞的不是加一行限制,而是 Buffalo 中间件顺序不可见、Body 消费不可逆、multipart 解析隐式触发——这些细节一旦漏掉一个,限制就形同虚设。

















