Displaying a 404 custom error page with the standard http package

Assuming we have:

http.HandleFunc("/smth", smthPage) http.HandleFunc("/", homePage) 

The user sees that “404 page not found” when they use the wrong URL. How can I return a custom page for this case?

Update on gorilla / mux

The accepted answer is suitable for those who use a clean network / http packet.

If you are using gorilla / mux, you should use something like this:

 func main() { r := mux.NewRouter() r.NotFoundHandler = http.HandlerFunc(notFound) } 

And implement func notFound(w http.ResponseWriter, r *http.Request) as you want.

+57
go
Apr 03 2018-12-12T00:
source share
6 answers

I usually do this:

 package main import ( "fmt" "net/http" ) func main() { http.HandleFunc("/", homeHandler) http.HandleFunc("/smth/", smthHandler) http.ListenAndServe(":12345", nil) } func homeHandler(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { errorHandler(w, r, http.StatusNotFound) return } fmt.Fprint(w, "welcome home") } func smthHandler(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/smth/" { errorHandler(w, r, http.StatusNotFound) return } fmt.Fprint(w, "welcome smth") } func errorHandler(w http.ResponseWriter, r *http.Request, status int) { w.WriteHeader(status) if status == http.StatusNotFound { fmt.Fprint(w, "custom 404") } } 

Here, I have simplified the code to show only 404, but actually I do more with this setting: I handle all HTTP errors with errorHandler , in which I write useful information and send e-mail to myself.

+54
Apr 03 '12 at 21:00
source
— -

You just need to create your own notFound handler and register it with HandleFunc for the path you are not processing.

If you want to control your routing logic the most, you will need to use your own server and your own handler type.

This allows you to implement more complex routing logic than HandleFunc allows.

+3
Apr 03 '12 at 18:37
source

The following is the approach that I choose. It is based on a piece of code that I can’t confirm because I’ve lost my browser bookmark.

Code example: (I put it in my main package)

 type hijack404 struct { http.ResponseWriter R *http.Request Handle404 func (w http.ResponseWriter, r *http.Request) bool } func (h *hijack404) WriteHeader(code int) { if 404 == code && h.Handle404(h.ResponseWriter, hR) { panic(h) } h.ResponseWriter.WriteHeader(code) } func Handle404(handler http.Handler, handle404 func (w http.ResponseWriter, r *http.Request) bool) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ hijack := &hijack404{ ResponseWriter:w, R: r, Handle404: handle404 } defer func() { if p:=recover(); p!=nil { if p==hijack { return } panic(p) } }() handler.ServeHTTP(hijack, r) }) } func fire404(res http.ResponseWriter, req *http.Request) bool{ fmt.Fprintf(res, "File not found. Please check to see if your URL is correct."); return true; } func main(){ handler_statics := http.StripPrefix("/static/", http.FileServer(http.Dir("/Path_To_My_Static_Files"))); var v_blessed_handler_statics http.Handler = Handle404(handler_statics, fire404); http.Handle("/static/", v_blessed_handler_statics); // add other handlers using http.Handle() as necessary if err := http.ListenAndServe(":8080", nil); err != nil{ log.Fatal("ListenAndServe: ", err); } } 

Please configure func fire404 to display its own version of the message for 404 error.

If you are using Gorilla Mux, you can replace the main function below:

 func main(){ handler_statics := http.StripPrefix("/static/", http.FileServer(http.Dir("/Path_To_My_Static_Files"))); var v_blessed_handler_statics http.Handler = Handle404(handler_statics, fire404); r := mux.NewRouter(); r.PathPrefix("/static/").Handler(v_blessed_handler_statics); // add other handlers with r.HandleFunc() if necessary... http.Handle("/", r); log.Fatal(http.ListenAndServe(":8080", nil)); } 

Please feel free to correct the code if it is incorrect, as I am only new to Go. Thank.

+3
Sep 15 '14 at 9:00
source

An ancient thread, but I just did something to intercept http.ResponseWriter , it may be appropriate here.

 package main //GAE POC originally inspired by https://thornelabs.net/2017/03/08/use-google-app-engine-and-golang-to-host-a-static-website-with-same-domain-redirects.html import ( "net/http" ) func init() { http.HandleFunc("/", handler) } // HeaderWriter is a wrapper around http.ResponseWriter which manipulates headers/content based on upstream response type HeaderWriter struct { original http.ResponseWriter done bool } func (hw *HeaderWriter) Header() http.Header { return hw.original.Header() } func (hw *HeaderWriter) Write(b []byte) (int, error) { if hw.done { //Silently let caller think they are succeeding in sending their boring 404... return len(b), nil } return hw.original.Write(b) } func (hw *HeaderWriter) WriteHeader(s int) { if hw.done { //Hmm... I don't think this is needed... return } if s < 400 { //Set CC header when status is < 400... //TODO: Use diff header if static extensions hw.original.Header().Set("Cache-Control", "max-age=60, s-maxage=2592000, public") } hw.original.WriteHeader(s) if s == 404 { hw.done = true hw.original.Write([]byte("This be custom 404...")) } } func handler(w http.ResponseWriter, r *http.Request) { urls := map[string]string{ "/example-post-1.html": "https://example.com/post/example-post-1.html", "/example-post-2.html": "https://example.com/post/example-post-2.html", "/example-post-3.html": "https://example.com/post/example-post-3.html", } w.Header().Set("Strict-Transport-Security", "max-age=15768000") //TODO: Put own logic if value, ok := urls[r.URL.Path]; ok { http.Redirect(&HeaderWriter{original: w}, r, value, 301) } else { http.ServeFile(&HeaderWriter{original: w}, r, "static/"+r.URL.Path) } } 
+2
Mar 10 '17 at 18:04 on
source

Maybe I'm wrong, but I just checked the sources: http://golang.org/src/pkg/net/http/server.go

It seems that specifying a custom NotFound () function is hardly possible: NotFoundHandler () returns a hard-coded NotFound () function.

You should probably send a message about this.

As a workaround, you can use the "/" handler, which is the backup if no other handlers are found (since this is the shortest). So, check if the page exists in this handler and returns a 404 user error.

+1
Apr 03 2018-12-12T00:
source

you can define

 http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { if request.URL.Path != "/" { writer.WriteHeader(404) writer.Write([]byte('not found, da xiong dei !!!')) return } }) 

when access is not found, the resource will be executed on http.HandleFunc ("/", xxx)

0
May 13, '19 at 3:57
source



All Articles