Ce face net/http.MaxBytesReader
Fără limită, un client poate trimite un corp de câțiva gigaocteți și serverul îl citește tot în memorie. r.Body = http.MaxBytesReader(w, r.Body, 1<<20) înlocuiește corpul cu unul care permite cel mult 1 MB; la depășire, citirea returnează o eroare de tip *http.MaxBytesError, iar serverul închide conexiunea după răspuns.
Se pune la începutul handler-ului, înainte de ParseForm, FormValue sau json.NewDecoder(r.Body). Eroarea se recunoaște cu errors.As (sau errors.AsType) și se răspunde de obicei cu 413 Request Entity Too Large.
Parametri
| Parametru | Descriere |
|---|---|
w |
Răspunsul (folosit ca să închidă conexiunea la depășire). |
r |
Corpul original, r.Body. |
n |
Numărul maxim de octeți permis. |
Ce returnează
Un io.ReadCloser limitat, care se pune în locul lui r.Body.
Exemple
Exemplul 1: Comentarii de maximum 50 de octeți
package main
import (
"errors"
"fmt"
"io"
"net/http"
"net/http/httptest"
"strings"
)
func comentariu(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, 50)
text, err := io.ReadAll(r.Body)
if mbe, ok := errors.AsType[*http.MaxBytesError](err); ok {
http.Error(w, fmt.Sprintf("comentariu prea lung (maximum %d octeți)", mbe.Limit), http.StatusRequestEntityTooLarge)
return
}
fmt.Fprintf(w, "comentariu salvat: %s", text)
}
func main() {
for _, text := range []string{"Articol foarte util, mulțumesc!", strings.Repeat("bla ", 30)} {
rec := httptest.NewRecorder()
comentariu(rec, httptest.NewRequest("POST", "/comentarii", strings.NewReader(text)))
fmt.Printf("%d %s\n", rec.Code, strings.TrimSpace(rec.Body.String()))
}
}
Rezultat
200 comentariu salvat: Articol foarte util, mulțumesc!
413 comentariu prea lung (maximum 50 octeți)
Exemplul 2: Limită pentru un corp JSON
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
)
func main() {
h := func(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, 64)
var date map[string]any
if err := json.NewDecoder(r.Body).Decode(&date); err != nil {
http.Error(w, "cerere invalidă: "+err.Error(), http.StatusBadRequest)
return
}
fmt.Fprint(w, "primit: ", date)
}
for _, corp := range []string{`{"nume":"Ana"}`, `{"descriere":"` + strings.Repeat("x", 100) + `"}`} {
rec := httptest.NewRecorder()
h(rec, httptest.NewRequest("POST", "/", strings.NewReader(corp)))
fmt.Println(rec.Code, strings.TrimSpace(rec.Body.String()))
}
}
Rezultat
200 primit: map[nume:Ana]
400 cerere invalidă: http: request body too large
Greșeli frecvente
- Creezi lectorul limitat, dar citești tot din
r.Bodyoriginal: limita nu se aplică. Atribuie rezultatul înapoi luir.Body. - Folosești
io.LimitReader: taie corpul în tăcere, fără eroare, și procesezi date trunchiate ca și cum ar fi complete.
Comenzi înrudite
net/http.Request.FormValue: FormValue citește un câmp dintr-un formular sau din query string; ParseForm le citește pe toate în r.Form și r.PostForm.encoding/json.NewDecoder: Creează un Decoder care citește JSON dintr-un io.Reader (corpul unei cereri, un fișier); Decode citește o valoare.net/http.Error: Error trimite un răspuns de eroare cu cod și mesaj text; NotFound trimite 404; StatusText dă textul unui cod (404 → Not Found).