Отображение пользовательской страницы ошибки 404 со стандартным пакетом http
предполагая, что мы имеем:
http.HandleFunc("/smth", smthPage)
http.HandleFunc("/", homePage)
пользователь видит простой "404 страница не найдена", когда они пытаются неправильный URL. Как я могу вернуть пользовательскую страницу для этого случая?
обновление, касающееся gorilla / mux
принятый ответ в порядке для тех, кто использует чистый пакет net / http.
Если вы используете gorilla/mux, вы должны использовать что-то вроде этого:
func main() {
r := mux.NewRouter()
r.NotFoundHandler = http.HandlerFunc(notFound)
}
и реализовать func notFound(w http.ResponseWriter, r *http.Request)
Как вы хотите.
5 ответов:
Я обычно делаю так:
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") } }
здесь я упростил код, чтобы показать только пользовательский 404, но на самом деле я делаю больше с этой настройкой: я обрабатываю все ошибки HTTP с помощью
errorHandler
, в котором я регистрирую полезную информацию и отправляю электронную почту себе.
вам просто нужно создать свой собственный обработчик notFound и зарегистрировать его с помощью HandleFunc для пути, который вы не обрабатываете.
Если вы хотите максимально контролировать свою логику маршрутизации, вам нужно будет использовать собственный сервер и собственный тип обработчика.
Это позволяет реализовать более сложные логика маршрутизации, чем HandleFunc позволит вам сделать.
следующий подход я выбираю. Он основан на фрагменте кода, который я не могу подтвердить, так как я потерял закладку браузера.
пример кода : (я положил его в мой основной пакет)
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, h.R) { 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); } }
пожалуйста, настроить
func fire404
для вывода собственной версии сообщения об ошибке 404.Если вам случится быть с помощью горилла мультиплексирования, вы, возможно, пожелает заменить основной функции ниже :
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)); }
пожалуйста, исправьте код, если это неправильно, так как я только новичок, чтобы пойти. Спасибо.
древняя нить, но я только что сделал что-то, чтобы перехватить
http.ResponseWriter
, может быть уместным здесь.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) } }
может быть, я ошибаюсь, но я просто проверил Источники:http://golang.org/src/pkg/net/http/server.go
кажется, что указание пользовательской функции NotFound() вряд ли возможно: NotFoundHandler () возвращает жестко закодированную функцию с именем NotFound ().
Вероятно, вы должны представить вопрос об этом.
в качестве обходного пути вы можете использовать свой обработчик"/", который является резервным, если никакие другие обработчики не были найдены (поскольку это самый короткий). Так, проверка страница существует в этом обработчике и возвращает пользовательскую ошибку 404.