net/http.FileServer în Go

FileServer servește fișierele dintr-un director (CSS, imagini, JS); StripPrefix taie prefixul URL-ului înainte.

Sintaxă
func FileServer(root FileSystem) Handler
func Dir(dir string) FileSystem   // http.Dir("static")
func StripPrefix(prefix string, h Handler) Handler

Ce face net/http.FileServer

http.FileServer(http.Dir("static")) creează un handler care răspunde cu fișierele din directorul static: setează tipul de conținut după extensie, suportă cache (If-Modified-Since), descărcări parțiale și afișează lista de fișiere pentru directoare. Pentru / caută index.html.

Problema obișnuită: ruta este /static/, dar fișierele stau direct în director, fără „static” în cale. http.StripPrefix("/static/", h) taie prefixul din URL înainte să dea cererea lui h, deci /static/stil.css devine stil.css. Cererile care nu încep cu prefixul primesc 404.

Din Go 1.22 există și http.FileServerFS(fsys), care primește un fs.FS, de exemplu fișiere incluse în program cu //go:embed.

Parametri

Parametru Descriere
root Sistemul de fișiere servit, de obicei http.Dir("director").
prefix Prefixul tăiat din calea cererii.

Ce returnează

Un http.Handler.

Exemple

Exemplul 1: Fișiere statice sub /static/

Exemplul creează directorul și fișierele, apoi le cere prin server.

package main

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

func main() {
	os.MkdirAll("public/css", 0o755)
	os.WriteFile("public/css/stil.css", []byte("body { color: navy; }"), 0o644)
	os.WriteFile("public/index.html", []byte("<h1>Bun venit</h1>"), 0o644)

	mux := http.NewServeMux()
	mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("public"))))
	srv := httptest.NewServer(mux)
	defer srv.Close()

	for _, cale := range []string{"/static/css/stil.css", "/static/", "/static/lipsa.png"} {
		resp, err := http.Get(srv.URL + cale)
		if err != nil {
			fmt.Println(err)
			return
		}
		corp, _ := io.ReadAll(resp.Body)
		resp.Body.Close()
		fmt.Printf("%-21s %d %-25s %s", cale, resp.StatusCode, resp.Header.Get("Content-Type"), corp)
		fmt.Println()
	}
}

Rezultat

/static/css/stil.css  200 text/css; charset=utf-8   body { color: navy; }
/static/              200 text/html; charset=utf-8  <h1>Bun venit</h1>
/static/lipsa.png     404 text/plain; charset=utf-8 404 page not found

Exemplul 2: Ce face StripPrefix

package main

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

func main() {
	arata := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "handler-ul vede calea %q", r.URL.Path)
	})
	h := http.StripPrefix("/imagini/", arata)

	for _, cale := range []string{"/imagini/2026/mare.jpg", "/alte/poza.jpg"} {
		rec := httptest.NewRecorder()
		h.ServeHTTP(rec, httptest.NewRequest("GET", cale, nil))
		fmt.Println(cale, "->", rec.Code, rec.Body.String())
	}
}

Rezultat

/imagini/2026/mare.jpg -> 200 handler-ul vede calea "2026/mare.jpg"
/alte/poza.jpg -> 404 404 page not found

Greșeli frecvente

  • Uiți StripPrefix: /static/stil.css este căutat ca public/static/stil.css și răspunsul este 404.
  • Scrii prefixul fără bara finală într-o parte și cu ea în cealaltă (mux.Handle("/static/", http.StripPrefix("/static", ...))): căile rezultate încep cu / sau nu se potrivesc. Folosește același text în ambele locuri.
  • Servești directorul proiectului (http.Dir(".")): oricine poate descărca și codul sursă sau fișierele de configurare. Servește doar un director dedicat.

Comenzi înrudite

  • net/http.ServeFile: Trimite ca răspuns conținutul unui fișier anume, cu tipul de conținut și suportul de cache potrivite.
  • net/http.NewServeMux: Creează un router (ServeMux) propriu care alege handler-ul după metoda și calea cererii; HandleFunc și Handle adaugă rute.
  • net/http.Handler: Interfața oricărui obiect care răspunde la cereri HTTP (metoda ServeHTTP); HandlerFunc transformă o funcție în Handler.