Go: JSON を r.Body から直接デコードする前に http.MaxBytesReader で上限を付ける
json.NewDecoder(r.Body).Decode(&v) はクライアントが送ってきた分だけ読もうとする。先に r.Body = http.MaxBytesReader(w, r.Body, 1<<20) で上限をかけ、超えたら 413 を返す。
何が困るか
net/http のサーバーはリクエストボディのサイズを既定では制限しない。巨大なボディを送られると、デコード中にメモリを食い続ける(悪意がなくても、誤ったアップロードで起きる)。
書き方
go
func handler(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, 1<<20) // 1 MiB
var in Input
if err := json.NewDecoder(r.Body).Decode(&in); err != nil {
var mbe *http.MaxBytesError
if errors.As(err, &mbe) {
http.Error(w, "request body too large", http.StatusRequestEntityTooLarge) // 413
return
}
http.Error(w, "bad request", http.StatusBadRequest)
return
}
// ...
}- 上限を超えて読もうとすると
*http.MaxBytesErrorが返る(Go 1.19 以降)。errors.Asで見分けて 413 にできる。 MaxBytesReaderは上限超過時にサーバーへ「この接続は閉じてよい」と伝えるので、残りのボディを読み続けずに済む。
注意点
- 全ハンドラに付けるならミドルウェアにまとめる。ファイルアップロードなど大きいボディを受けるルートだけ別の上限にする。
- リバースプロキシ(nginx の
client_max_body_sizeなど)にも上限があれば二重で守れるが、アプリ側の上限は残しておく。
出典
- @amitsinha__07 · 2026-10-22
- net/http ドキュメント
MaxBytesReader: pkg.go.dev