Reputation: 901
I'm running into the following problem with Go and gorilla/mux
routers when building a simple API. I'm sure it's the usual stupid mistake that is right on my face, but I can't see it.
|--main.go
|
|--public/--index.html
| |--image.png
|
|--img/--img1.jpg
| |--img2.jpg
| |--...
|...
main.go
package main
import (
"net/http"
"github.com/gorilla/mux"
)
var Router = mux.NewRouter()
func InitRouter() {
customers := Router.PathPrefix("/customers").Subrouter()
customers.HandleFunc("/all", getAllCustomers).Methods("GET")
customers.HandleFunc("/{customerId}", getCustomer).Methods("GET")
// ...
// Registering whatever middleware
customers.Use(middlewareFunc)
users := Router.PathPrefix("/users").Subrouter()
users.HandleFunc("/register", registerUser).Methods("POST")
users.HandleFunc("/login", loginUser).Methods("POST")
// ...
// Static files (customer pictures)
var dir string
flag.StringVar(&dir, "images", "./img/", "Directory to serve the images")
Router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
var publicDir string
flag.StringVar(&publicDir, "public", "./public/", "Directory to serve the homepage")
Router.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir(publicDir))))
}
func main() {
InitRouter()
// Other omitted configuration
server := &http.Server{
Handler: Router,
Addr: ":" + port,
// Adding timeouts
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
}
err := server.ListenAndServe()
// ...
}
Subroutes work OK, with middleware and all. The images under img
are correctly served if I go to localhost:5000/static/img1.png
.
The thing is, going to localhost:5000
serves the index.html
that resides in public
, but then localhost:5000/image.png
is a 404 not found
instead.
What is happening here?
Upvotes: 2
Views: 286
Reputation: 22027
Change this line:
// handles '/' and *ONLY* '/'
Router.Handle("/",
http.StripPrefix("/", http.FileServer(http.Dir(publicDir))))
To this:
// handles '/' and all sub-routes
Router.PathPrefix("/").Handler(
http.StripPrefix("/",http.FileServer(http.Dir(publicPath))))
Basically, in your original code, the router for /
is handling this path and only that path (no sub-routes).
You may wonder why your original code "worked" for at least one file (index.html
). The reason is the http.FileServer
given a path that is a directory - not a file - will default to serving the index page file index.html
(see FileServer
source).
Using PathPrefix
allows the (fileserver) handler to accept all URL paths below the path /
.
Upvotes: 1