Ce face net/http.ResponseWriter
Handler-ul primește un http.ResponseWriter (de obicei numit w) și scrie răspunsul prin el, în trei pași, în această ordine: setează antetele cu w.Header().Set(...), trimite codul de stare cu w.WriteHeader(201), apoi scrie corpul cu w.Write, fmt.Fprintf(w, ...) sau json.NewEncoder(w).Encode(...).
Ordinea contează: primul Write trimite automat codul 200 și antetele, iar după acel moment schimbările de antete și un nou WriteHeader sunt ignorate (Go afișează în jurnal superfluous response.WriteHeader call). Dacă nu setezi Content-Type, Go îl ghicește din primii 512 octeți ai corpului.
Ce returnează
Header() returnează harta de antete a răspunsului. Write returnează numărul de octeți scriși și o eroare.
Exemple
Exemplul 1: Antete, cod de stare și corp
package main
import (
"fmt"
"net/http"
"net/http/httptest"
)
func creeazaComanda(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Set("Location", "/comenzi/1001")
w.WriteHeader(http.StatusCreated)
fmt.Fprint(w, `{"id": 1001, "stare": "nouă"}`)
}
func main() {
rec := httptest.NewRecorder()
creeazaComanda(rec, httptest.NewRequest("POST", "/comenzi", nil))
rez := rec.Result()
fmt.Println("Status: ", rez.Status)
fmt.Println("Tip: ", rez.Header.Get("Content-Type"))
fmt.Println("Location:", rez.Header.Get("Location"))
fmt.Println("Corp: ", rec.Body.String())
}
Rezultat
Status: 201 Created
Tip: application/json; charset=utf-8
Location: /comenzi/1001
Corp: {"id": 1001, "stare": "nouă"}
Exemplul 2: Tipul de conținut ghicit și ordinea greșită
Primul răspuns nu setează Content-Type, deci Go îl deduce. În al doilea, antetul și codul sunt setate după Write și se pierd.
package main
import (
"fmt"
"net/http"
"net/http/httptest"
)
func main() {
html := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "<!DOCTYPE html><h1>Salut</h1>")
})
rec := httptest.NewRecorder()
html.ServeHTTP(rec, httptest.NewRequest("GET", "/", nil))
fmt.Println("Ghicit:", rec.Header().Get("Content-Type"))
gresit := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("text"))
w.Header().Set("X-Versiune", "2") // prea târziu
})
rec = httptest.NewRecorder()
gresit.ServeHTTP(rec, httptest.NewRequest("GET", "/", nil))
rez := rec.Result()
fmt.Println("Cod:", rez.StatusCode, "X-Versiune:", rez.Header.Get("X-Versiune") == "")
}
Rezultat
Ghicit: text/html; charset=utf-8
Cod: 200 X-Versiune: true
Greșeli frecvente
- Setezi antete după ce ai scris corpul. Antetele și codul pleacă la primul
Write; setează-le înainte. - Apelezi
w.WriteHeader(http.StatusOK)dupăhttp.Errorsau dupăWrite: apare avertismentulsuperfluous response.WriteHeader callși codul nu se schimbă. - Uiți
returndupă un răspuns de eroare și handler-ul continuă să scrie în același răspuns.
Comenzi înrudite
net/http.Header: Antetele unei cereri sau ale unui răspuns: Get citește, Set înlocuiește, Add adaugă încă o valoare, Del șterge.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).net/http.Handler: Interfața oricărui obiect care răspunde la cereri HTTP (metoda ServeHTTP); HandlerFunc transformă o funcție în Handler.encoding/json.NewEncoder: Creează un Encoder care scrie JSON direct într-un io.Writer (răspuns HTTP, fișier, ecran); Encode scrie o valoare.