My code for a simple file server:
package main
import (
"net/http"
"os"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
// default file handler
r.Handle("/", http.FileServer(http.Dir("web")))
// run on port 8080
if err := http.ListenAndServe(":8080", handlers.LoggingHandler(os.Stdout, r)); err != nil {
panic(err)
}
}
My directory structure is:
cmd/server/main.go
web/index.html
web/favicon.ico
web/favicon.png
web/css/main.css
index.html
asks for main.css
. so when I run go run cmd/server/main.go
I get the following output:
127.0.0.1 - - [24/Dec/2019:22:45:26 -0X00] "GET / HTTP/1.1" 304 0
127.0.0.1 - - [24/Dec/2019:22:45:26 -0X00] "GET /css/main.css HTTP/1.1" 404 19
I'm able to see the index.html
page, but without the CSS. When I request any other file (e.g. favicon.ico
) I also get a 404. Why does my FileServer
only serve index.html
?
To demonstrate why this does not work consider the following test app:
package main
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
)
type testHandler struct{}
func (h *testHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Printf("Got request for %s\n", r.URL)
}
func main() {
r := mux.NewRouter()
hndlr := testHandler{}
r.Handle("/", &hndlr)
// run on port 8080
if err := http.ListenAndServe(":8080", r); err != nil {
panic(err)
}
}
If you run this and access http://127.0.0.1:8080/
in your browser it will log Got request for /
. However if you access http://127.0.0.1:8080/foo
you will get a 404 error and nothing will be logged. This is because r.Handle("/", &hndlr)
will only match on /
and not anything below it.
If you change this to r.PathPrefix("/").Handler(&hndlr)
then it will work as you expect (the router will pass all paths to the handler). So to fix your example change r.Handle("/", http.FileServer(http.Dir("web")))
to r.PathPrefix("/").Handler( http.FileServer(http.Dir("web")))
.
Note: Because this is passing all paths to FileServer
there is really no need to use Gorilla Mux; I have left this in on the assumption that you will be using it to add some other routes.