io.NopCloser în Go

Transformă un Reader obișnuit într-un io.ReadCloser al cărui Close nu face nimic.

Sintaxă
func NopCloser(r Reader) ReadCloser

Ce face io.NopCloser

Unele funcții și câmpuri cer un io.ReadCloser (de exemplu http.Request.Body sau http.Response.Body), dar tu ai doar un strings.Reader sau un bytes.Buffer, care nu au Close. io.NopCloser(r) adaugă o metodă Close care returnează mereu nil.

Este foarte folosit în teste (corpuri HTTP false) și când citești un corp de cerere, îl păstrezi și apoi îl pui la loc pentru alt cod. Înainte de Go 1.16 funcția se numea ioutil.NopCloser. Dacă r are și metoda WriteTo, rezultatul o păstrează.

Parametri

Parametru Descriere
r Reader-ul de învelit.

Ce returnează

Un io.ReadCloser.

Exemple

Exemplul 1: Corp de cerere pentru un test

package main

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

func main() {
    req, _ := http.NewRequest("POST", "https://exemplu.ro/comenzi", nil)
    req.Body = io.NopCloser(strings.NewReader(`{"produs":"cafea","cantitate":2}`))

    corp, _ := io.ReadAll(req.Body)
    fmt.Println(string(corp))
    fmt.Println("Close:", req.Body.Close())
}

Rezultat

{"produs":"cafea","cantitate":2}
Close: <nil>

Exemplul 2: Citirea unui corp și punerea lui la loc

După io.ReadAll corpul este consumat. Îl punem la loc, ca alt cod să-l poată citi din nou.

package main

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

func jurnalizeaza(req *http.Request) {
    date, _ := io.ReadAll(req.Body)
    req.Body.Close()
    fmt.Println("jurnal:", string(date))
    req.Body = io.NopCloser(bytes.NewReader(date)) // la loc
}

func main() {
    req, _ := http.NewRequest("POST", "/plata", strings.NewReader(`{"suma":249.9}`))
    jurnalizeaza(req)
    corp, _ := io.ReadAll(req.Body)
    fmt.Println("handler:", string(corp))
}

Rezultat

jurnal: {"suma":249.9}
handler: {"suma":249.9}

Greșeli frecvente

  • Folosești NopCloser pe un fișier sau o conexiune ca să „scapi” de Close. Resursa reală nu mai este închisă niciodată.

Comenzi înrudite

  • io.Closer: Interfața pentru orice resursă care trebuie închisă după folosire (fișiere, conexiuni, corpuri HTTP).
  • io.Reader: Interfața pentru orice sursă de date din care se poate citi: fișiere, text, conexiuni, răspunsuri HTTP.
  • io.ReadAll: Citește tot ce oferă un Reader, până la final, și returnează datele ca slice de octeți.