Ce face net/http.Request
Pe server, handler-ul primește r *http.Request cu tot ce a trimis clientul: r.Method (GET, POST…), r.URL.Path și r.URL.Query(), antetele în r.Header, corpul în r.Body (un flux pe care îl citești o singură dată), adresa clientului în r.RemoteAddr. Pe client, aceeași structură descrie cererea pe care o trimiți (o creezi cu http.NewRequest).
r.Context() returnează contextul cererii. Pe server, acesta se anulează când clientul închide conexiunea sau cererea se termină; dă-l mai departe interogărilor și apelurilor lente, ca să nu lucrezi degeaba pentru un client care a plecat. Pe client, este contextul dat la NewRequestWithContext.
Ce returnează
Context() returnează un context.Context (niciodată nil).
Exemple
Exemplul 1: Câmpurile unei cereri
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"strings"
)
func main() {
arata := func(w http.ResponseWriter, r *http.Request) {
corp, _ := io.ReadAll(r.Body)
fmt.Println("Metoda: ", r.Method)
fmt.Println("Cale: ", r.URL.Path)
fmt.Println("Query: ", r.URL.Query())
fmt.Println("Host: ", r.Host)
fmt.Println("Agent: ", r.Header.Get("User-Agent"))
fmt.Println("Tip corp:", r.Header.Get("Content-Type"))
fmt.Println("Corp: ", string(corp))
}
req := httptest.NewRequest("PUT", "http://magazin.local/produse/17?moneda=lei",
strings.NewReader(`{"pret": 32.5}`))
req.Header.Set("User-Agent", "aplicatie-mobila/2.1")
req.Header.Set("Content-Type", "application/json")
arata(httptest.NewRecorder(), req)
}
Rezultat
Metoda: PUT
Cale: /produse/17
Query: map[moneda:[lei]]
Host: magazin.local
Agent: aplicatie-mobila/2.1
Tip corp: application/json
Corp: {"pret": 32.5}
Exemplul 2: Contextul cererii: clientul a renunțat
Clientul are răbdare 50 ms. Handler-ul urmărește r.Context() și se oprește când conexiunea este închisă.
package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"time"
)
func main() {
oprit := make(chan error, 1)
lent := func(w http.ResponseWriter, r *http.Request) {
select {
case <-time.After(2 * time.Second):
fmt.Fprint(w, "raport gata")
oprit <- nil
case <-r.Context().Done():
oprit <- r.Context().Err()
}
}
srv := httptest.NewServer(http.HandlerFunc(lent))
defer srv.Close()
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, "GET", srv.URL, nil)
_, err := http.DefaultClient.Do(req)
fmt.Println("Clientul a primit:", err != nil)
fmt.Println("Handler-ul s-a oprit:", <-oprit)
}
Rezultat
Clientul a primit: true
Handler-ul s-a oprit: context canceled
Greșeli frecvente
- Citești
r.Bodyde două ori (de exemplu o dată pentru jurnal, apoi pentru JSON). A doua citire este goală; citește o dată în[]byteși folosește copia. - Folosești
context.Background()în handler pentru interogări: dacă clientul pleacă, interogarea continuă degeaba. Foloseșter.Context(). - Te bazezi pe
r.RemoteAddrpentru IP-ul real în spatele unui proxy (Nginx, Cloudflare): este adresa proxy-ului.
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.net/http.Request.PathValue: Returnează valoarea unui parametru din calea rutei, de exemplu id din modelul „/produse/{id}”.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.NewRequest: Construiește o cerere HTTP completă (orice metodă, antete, corp) care se trimite apoi cu Client.Do.context.Context: Interfața care duce prin program semnalul de anulare, termenul limită și valori legate de o cerere (ctx).