Log 404 on http.FileServer

2020-04-11 17:55发布

问题:

I'm serving jpeg images from dirPath using http.FileServer with:

http.Handle("/o/", http.StripPrefix(
    path.Join("/o", dirPath), http.FileServer(http.Dir(dirPath))))

What I don't understand is how to log when a request is made for a file that does not exist. I can see http.FileServer returning 404 page not found when I make a request with the browser, but not on the server console.

回答1:

The http.Handlers returned by http.StripPrefix() and http.FileServer() do not log HTTP 404 errors. You have to extend their functionality in order to achieve what you want.

We can wrap the http.Handler value returned by http.StripPrefix() or http.FileServer() in another http.Handler or http.HandlerFunc. Once you wrapped the handler, register the wrapper of course.

The wrapper implementation will simply called the wrapped one, and once it returns, can inspect the HTTP response status code. If it is an error (or specifically HTTP 404 Not Found), can log it appropriately.

Problem is http.ResponseWriter does not support reading the response status code. What we can do is we also wrap the http.ResponseWriter and when status code is written, we will store it for later to be available.

Our http.ResponseWriter wrapper:

type StatusRespWr struct {
    http.ResponseWriter // We embed http.ResponseWriter
    status int
}

func (w *StatusRespWr) WriteHeader(status int) {
    w.status = status // Store the status for our own use
    w.ResponseWriter.WriteHeader(status)
}

And wrapping the http.Handler:

func wrapHandler(h http.Handler) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        srw := &StatusRespWr{ResponseWriter: w}
        h.ServeHTTP(srw, r)
        if srw.status >= 400 { // 400+ codes are the error codes
            log.Printf("Error status code: %d when serving path: %s",
                srw.status, r.RequestURI)
        }
    }
}

And the main function creating a file server, wrapping it and registering it:

http.HandleFunc("/o/", wrapHandler(
    http.StripPrefix("/o", http.FileServer(http.Dir("/test")))))
panic(http.ListenAndServe(":8181", nil))

Example output when requesting a non-existing file:

2015/12/01 11:47:40 Error status code: 404 when serving path: /o/sub/b.txt2