net/http.Post în Go

Post trimite date (ex. JSON) cu tipul de conținut dat; PostForm trimite un formular codat ca application/x-www-form-urlencoded.

Sintaxă
func Post(url, contentType string, body io.Reader) (resp *Response, err error)
func PostForm(url string, data url.Values) (resp *Response, err error)

Ce face net/http.Post

http.Post(url, "application/json", corp) trimite o cerere POST cu corpul citit din corp (orice io.Reader: strings.NewReader, bytes.NewReader, un fișier). Al doilea parametru devine antetul Content-Type, ca serverul să știe cum să citească datele.

http.PostForm(url, valori) codează un url.Values ca formular (nume=Ana&oras=Ia%C8%99i) și setează singur tipul. Este ce trimite un formular HTML obișnuit.

Ca la http.Get: folosesc clientul implicit, fără limită de timp; un cod 4xx/5xx nu este err; corpul răspunsului trebuie închis. Pentru alte metode (PUT, DELETE) sau antete proprii folosește http.NewRequest și Client.Do.

Parametri

Parametru Descriere
url Adresa la care trimiți.
contentType Tipul datelor: "application/json", "text/plain" etc.
body / data Corpul cererii (io.Reader) sau câmpurile formularului (url.Values).

Ce returnează

Răspunsul și o eroare, ca la http.Get.

Exemple

Exemplul 1: Trimiterea unui JSON

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
)

type Comanda struct {
	Produs string `json:"produs"`
	Bucati int    `json:"bucati"`
}

func main() {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var c Comanda
		if err := json.NewDecoder(r.Body).Decode(&c); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		w.WriteHeader(http.StatusCreated)
		fmt.Fprintf(w, "primit %s: %d x %s", r.Header.Get("Content-Type"), c.Bucati, c.Produs)
	}))
	defer srv.Close()

	date, _ := json.Marshal(Comanda{Produs: "cafea", Bucati: 2})
	resp, err := http.Post(srv.URL+"/comenzi", "application/json", bytes.NewReader(date))
	if err != nil {
		fmt.Println(err)
		return
	}
	defer resp.Body.Close()
	corp, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.Status)
	fmt.Println(string(corp))
}

Rezultat

201 Created
primit application/json: 2 x cafea

Exemplul 2: Formular cu PostForm

package main

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

func main() {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Content-Type: %s\nnume=%s, oras=%s\n",
			r.Header.Get("Content-Type"), r.FormValue("nume"), r.FormValue("oras"))
	}))
	defer srv.Close()

	date := url.Values{}
	date.Set("nume", "Ana Popescu")
	date.Set("oras", "Iași")
	resp, err := http.PostForm(srv.URL+"/abonare", date)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer resp.Body.Close()
	corp, _ := io.ReadAll(resp.Body)
	fmt.Print(string(corp))
	fmt.Println("Corp trimis:", date.Encode())
}

Rezultat

Content-Type: application/x-www-form-urlencoded
nume=Ana Popescu, oras=Iași
Corp trimis: nume=Ana+Popescu&oras=Ia%C8%99i

Greșeli frecvente

  • Trimiți JSON cu tipul "text/plain" sau fără tip: multe servere refuză cererea sau nu o citesc.
  • Trimiți formularul cu http.Post și scrii singur textul fără codare ("nume=Ana Pop&oras=Iași"): spațiile și diacriticele ajung greșit. Folosește PostForm sau url.Values.Encode.

Comenzi înrudite

  • net/http.Get: Trimite o cerere GET (sau HEAD, doar antete) la adresa dată și returnează răspunsul; corpul trebuie închis.
  • net/http.NewRequest: Construiește o cerere HTTP completă (orice metodă, antete, corp) care se trimite apoi cu Client.Do.
  • net/url.Values: Parametrii unui query string sau ai unui formular: Get, Set, Add, Del, Has și Encode (codare sortată după cheie).
  • encoding/json.Marshal: Transformă o valoare Go (structură, map, slice) în JSON compact; etichetele json:”…” aleg numele și regulile câmpurilor.