net/http.NewRequest în Go

Construiește o cerere HTTP completă (orice metodă, antete, corp) care se trimite apoi cu Client.Do.

Sintaxă
func NewRequest(method, url string, body io.Reader) (*Request, error)
func NewRequestWithContext(ctx context.Context, method, url string, body io.Reader) (*Request, error)   // Go 1.13

Ce face net/http.NewRequest

Când http.Get și http.Post nu ajung (ai nevoie de PUT sau DELETE, de antete ca Authorization, de un context), construiești cererea cu http.NewRequest(metoda, url, corp), îi setezi antetele în req.Header și o trimiți cu client.Do(req). Pentru cereri fără corp, body este nil.

http.NewRequestWithContext(ctx, ...) leagă cererea de un context: dacă contextul este anulat sau expiră, cererea este întreruptă, inclusiv citirea corpului răspunsului. În cod nou, preferă această variantă; NewRequest folosește context.Background().

Funcția returnează eroare doar dacă metoda sau adresa sunt invalide; nicio cerere nu pleacă până la Do.

Parametri

Parametru Descriere
ctx Contextul care poate anula cererea (doar la NewRequestWithContext).
method Metoda: "GET", "POST", "PUT", "DELETE" sau constantele http.MethodGet etc.
url Adresa completă.
body Corpul cererii sau nil.

Ce returnează

Cererea (*http.Request) și o eroare.

Exemple

Exemplul 1: PUT cu antet de autentificare

package main

import (
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"strings"
)

func main() {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		corp, _ := io.ReadAll(r.Body)
		fmt.Fprintf(w, "%s %s\nAuthorization: %s\nCorp: %s\n", r.Method, r.URL.Path, r.Header.Get("Authorization"), corp)
	}))
	defer srv.Close()

	req, err := http.NewRequest(http.MethodPut, srv.URL+"/produse/17", strings.NewReader(`{"pret": 35}`))
	if err != nil {
		fmt.Println(err)
		return
	}
	req.Header.Set("Authorization", "Bearer token-secret")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer resp.Body.Close()
	raspuns, _ := io.ReadAll(resp.Body)
	fmt.Print(string(raspuns))

	_, err = http.NewRequest("GET", "://adresa gresita", nil)
	fmt.Println("URL invalid:", err)
}

Rezultat

PUT /produse/17
Authorization: Bearer token-secret
Corp: {"pret": 35}
URL invalid: parse "://adresa gresita": missing protocol scheme

Exemplul 2: Cerere anulată de context

package main

import (
	"context"
	"errors"
	"fmt"
	"net/http"
	"net/http/httptest"
	"time"
)

func main() {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		select {
		case <-time.After(time.Second):
		case <-r.Context().Done():
		}
	}))
	defer srv.Close()

	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
	defer cancel()
	req, _ := http.NewRequestWithContext(ctx, http.MethodGet, srv.URL, nil)
	_, err := http.DefaultClient.Do(req)
	fmt.Println("Eroare:", err != nil)
	fmt.Println("Din cauza limitei de timp:", errors.Is(err, context.DeadlineExceeded))
}

Rezultat

Eroare: true
Din cauza limitei de timp: true

Greșeli frecvente

  • Construiești cererea, dar uiți să o trimiți: NewRequest doar o pregătește; client.Do(req) o trimite.
  • Setezi antetul Host prin req.Header.Set("Host", ...): este ignorat. Folosește câmpul req.Host.

Comenzi înrudite

  • net/http.Client: Clientul HTTP configurabil (limită de timp, redirecționări, cookie-uri); Do trimite o cerere, Get o cerere GET.
  • net/http.Request: Structura unei cereri HTTP: metoda, URL-ul, antetele, corpul și contextul (Context()) care se anulează când clientul pleacă.
  • net/http.Header: Antetele unei cereri sau ale unui răspuns: Get citește, Set înlocuiește, Add adaugă încă o valoare, Del șterge.
  • context.WithTimeout: Creează un context care se anulează singur după durata dată; limita de timp standard pentru cereri și interogări.