net/http.Response în Go

Răspunsul primit de client: codul de stare (StatusCode, Status), antetele (Header) și corpul (Body), care trebuie închis.

Sintaxă
type Response struct {
    Status        string      // "200 OK"
    StatusCode    int         // 200
    Header        Header
    Body          io.ReadCloser
    ContentLength int64
    Request       *Request
    ...
}

Ce face net/http.Response

Funcțiile client (Get, Post, Client.Do) returnează un *http.Response. StatusCode este numărul (200, 404), Status textul complet ("404 Not Found"), Header antetele, iar Body corpul, citit ca flux (io.ReadAll, json.NewDecoder, io.Copy într-un fișier).

Body nu este niciodată nil când err == nil și trebuie închis întotdeauna, chiar dacă nu îl citești. ContentLength este mărimea anunțată (-1 dacă nu se știe), iar Request este cererea care a produs răspunsul (după redirecționări, ultima).

Pe server, același tip apare în teste: httptest.ResponseRecorder.Result() returnează un *http.Response.

Ce returnează

Este o structură; câmpurile ei se citesc direct.

Exemple

Exemplul 1: Câmpurile unui răspuns

package main

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

func main() {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.Header().Set("X-Total", "2")
		fmt.Fprint(w, `[{"oras":"Iași","temp":14},{"oras":"Cluj","temp":11}]`)
	}))
	defer srv.Close()

	resp, err := http.Get(srv.URL + "/meteo")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer resp.Body.Close()
	fmt.Println("Status:       ", resp.Status)
	fmt.Println("StatusCode:   ", resp.StatusCode)
	fmt.Println("Content-Type: ", resp.Header.Get("Content-Type"))
	fmt.Println("X-Total:      ", resp.Header.Get("X-Total"))
	fmt.Println("ContentLength:", resp.ContentLength)
	fmt.Println("Cererea:      ", resp.Request.Method, resp.Request.URL.Path)

	var vreme []struct {
		Oras string `json:"oras"`
		Temp int    `json:"temp"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&vreme); err != nil {
		fmt.Println(err)
		return
	}
	for _, v := range vreme {
		fmt.Printf("%s: %d °C\n", v.Oras, v.Temp)
	}
}

Rezultat

Status:        200 OK
StatusCode:    200
Content-Type:  application/json
X-Total:       2
ContentLength: 54
Cererea:       GET /meteo
Iași: 14 °C
Cluj: 11 °C

Exemplul 2: Clasificarea după codul de stare

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strconv"
)

func main() {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		cod, _ := strconv.Atoi(r.URL.Query().Get("cod"))
		w.WriteHeader(cod)
	}))
	defer srv.Close()

	for _, cod := range []string{"200", "204", "404", "503"} {
		resp, err := http.Get(srv.URL + "/?cod=" + cod)
		if err != nil {
			fmt.Println(err)
			return
		}
		resp.Body.Close()
		switch {
		case resp.StatusCode >= 200 && resp.StatusCode < 300:
			fmt.Println(resp.Status, "-> succes")
		case resp.StatusCode >= 400 && resp.StatusCode < 500:
			fmt.Println(resp.Status, "-> greșeala clientului")
		default:
			fmt.Println(resp.Status, "-> problemă la server, reîncearcă")
		}
	}
}

Rezultat

200 OK -> succes
204 No Content -> succes
404 Not Found -> greșeala clientului
503 Service Unavailable -> problemă la server, reîncearcă

Greșeli frecvente

  • Compari resp.Status == "200". Status este "200 OK"; compară resp.StatusCode == http.StatusOK.
  • Nu închizi Body pentru răspunsurile de eroare pe care nu le citești: conexiunea nu este eliberată.

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.Client: Clientul HTTP configurabil (limită de timp, redirecționări, cookie-uri); Do trimite o cerere, Get o cerere GET.
  • net/http.Header: Antetele unei cereri sau ale unui răspuns: Get citește, Set înlocuiește, Add adaugă încă o valoare, Del șterge.
  • 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.