Chi: NotFound ignored when FileServer using "/" path

Created on 13 Feb 2017  路  6Comments  路  Source: go-chi/chi

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?

Most helpful comment

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

All 6 comments

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

gpopovic picture gpopovic  路  5Comments

netsharec picture netsharec  路  6Comments

chenjie4255 picture chenjie4255  路  11Comments

MrXu picture MrXu  路  3Comments

mvrlin picture mvrlin  路  6Comments