Ce face net/http.ServeFile
http.ServeFile(w, r, "rapoarte/octombrie.pdf") răspunde cu fișierul dat. Ca și FileServer, deduce Content-Type din extensie, răspunde la cereri condiționate (304 Not Modified) și parțiale (Range), iar pentru un fișier inexistent trimite 404.
Este potrivit când tu alegi fișierul în cod, de exemplu după verificarea drepturilor utilizatorului. Ca protecție, ServeFile respinge cererile al căror URL conține ... Dacă numele fișierului vine de la utilizator, validează-l tu (sau folosește os.Root/http.FileServer), ca să nu poată cere fișiere din afara directorului.
Pentru ca browserul să descarce fișierul în loc să-l afișeze, setează înainte antetul Content-Disposition: attachment; filename=....
Parametri
| Parametru | Descriere |
|---|---|
name |
Calea fișierului pe disc (relativă la directorul curent sau absolută). |
Ce returnează
Nimic.
Exemple
Exemplul 1: Descărcarea unei facturi
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"os"
)
func main() {
os.WriteFile("factura-1001.txt", []byte("Factura 1001\nTotal: 249,90 lei\n"), 0o644)
descarca := func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Disposition", `attachment; filename="factura-1001.txt"`)
http.ServeFile(w, r, "factura-1001.txt")
}
rec := httptest.NewRecorder()
descarca(rec, httptest.NewRequest("GET", "/factura", nil))
fmt.Println("Cod:", rec.Code)
fmt.Println("Tip:", rec.Header().Get("Content-Type"))
fmt.Println("Disposition:", rec.Header().Get("Content-Disposition"))
fmt.Print(rec.Body.String())
}
Rezultat
Cod: 200
Tip: text/plain; charset=utf-8
Disposition: attachment; filename="factura-1001.txt"
Factura 1001
Total: 249,90 lei
Exemplul 2: Fișier inexistent și cerere cu ..
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"strings"
)
func main() {
rec := httptest.NewRecorder()
http.ServeFile(rec, httptest.NewRequest("GET", "/raport", nil), "nu-exista.pdf")
fmt.Println(rec.Code, strings.TrimSpace(rec.Body.String()))
rec = httptest.NewRecorder()
req := httptest.NewRequest("GET", "/x", nil)
req.URL.Path = "/../secret.txt"
http.ServeFile(rec, req, "main.go")
fmt.Println(rec.Code, strings.TrimSpace(rec.Body.String()))
}
Rezultat
404 404 page not found
400 invalid URL path
Greșeli frecvente
- Construiești calea din cererea utilizatorului:
http.ServeFile(w, r, "fisiere/" + r.URL.Query().Get("f")). Cuf=../../etc/passwdse poate citi orice fișier; verifică numele (de exemplu cufilepath.IsLocal).
Comenzi înrudite
net/http.FileServer: FileServer servește fișierele dintr-un director (CSS, imagini, JS); StripPrefix taie prefixul URL-ului înainte.net/http.ResponseWriter: Interfața prin care handler-ul construiește răspunsul: antete (Header), cod de stare (WriteHeader) și corp (Write).net/http.Header: Antetele unei cereri sau ale unui răspuns: Get citește, Set înlocuiește, Add adaugă încă o valoare, Del șterge.