When using FileServer with a root ("/") path, the NotFound method seems to get ignored...
r := chi.NewRouter()
workDir, _ := os.Getwd()
filesDir := filepath.Join(workDir, "public")
r.FileServer("/", http.Dir(filesDir))
r.NotFound(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(404)
w.Write([]byte("nothing here"))
})
An unknown route will always return the default "404 page not found" rather than the expected "nothing here". Changing the FileServer path to anything else (ie. "/foo") produces the expected "nothing here".
The goal is to be able to serve an Angular frontend at the root path, while all API routes are served via "/api/v1/". I also want to route any 404 traffic to the root to be able to better handle Angular routing if a user refreshes the page while within a frontend route.
Is the above an expected result or a bug? If expected, what would be the best way to go about doing what I'm looking for?
good question. I believe r.FileServer("/") will make a route on /* which catches every request to its handler. Potentially r.FileServer() impl could be changed to call r.NotFound() if a file is not found.
You do have the option to write the file serving handler yourself, the r.FileServer() is just a helper method. Please let me know if you solve it.
@pkieltyka locally, I just updated the mx.Get() call in r.FileServer() to check to see if the file exists before serving. It may not be the most efficient solution, but it's working as it should...
mx.Get(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if _, err := os.Stat(fmt.Sprintf("%s", root) + r.RequestURI); os.IsNotExist(err) {
mx.NotFoundHandler().ServeHTTP(w, r)
} else {
fs.ServeHTTP(w, r)
}
}))
Any interest in a pull request for it? (I would include tests)
thanks for letting me know, but not at this time. But that should let you keep going, just take your own FileServer function to register the handler
Cool. Here's my solution for a FileServer function that incorporates the pressly/chi NotFoundHandler for anyone that's interested...
workDir, _ := os.Getwd()
filesDir := filepath.Join(workDir, "public")
root := http.Dir(filesDir)
fs := http.StripPrefix("/", http.FileServer(root))
r.Get("/*", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if _, err := os.Stat(fmt.Sprintf("%s", root) + r.RequestURI); os.IsNotExist(err) {
r.NotFoundHandler().ServeHTTP(w, r)
} else {
fs.ServeHTTP(w, r)
}
}))
Thanks @pkieltyka
thanks @jsadwith
Just as a comment you would probably want to parse r.RequestURI as it will include the query string as well which you probably don't want when stating the file system
Most helpful comment
Cool. Here's my solution for a FileServer function that incorporates the pressly/chi NotFoundHandler for anyone that's interested...
Thanks @pkieltyka