2012-04-03 24 views
47

假設我們有錯誤頁面:顯示自定義404與標準的HTTP包

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

用戶看到一個簡單的「404找不到網頁」,當他們嘗試錯誤的URL。我怎樣才能返回這種情況下的自定義頁面?

更新有關大猩猩/ MUX

接受的答案是確定使用純淨/ HTTP包的。

如果使用大猩猩/ MUX你應該使用這樣的事情:

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

並實行func notFound(w http.ResponseWriter, r *http.Request),只要你想。

+3

+1感謝您的大猩猩/ mux快捷方式。可以用這個踢自己。 – eduncan911 2014-06-04 00:25:35

+0

是的,當一個問題預見到後續問題時總是很好的! – 2015-01-20 03:19:54

回答

46

我經常這樣做:

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,但實際上我在此設置做多:我處理所有與errorHandler的HTTP錯誤,我在其中記錄有用信息併發送電子郵件給我自己。

+2

由於至少Go 1.7這個答案仍然是正確的,但'模式'/'匹配所有不符合其他註冊模式的路徑'。在這個例子中,只有在homeHandler或「/」中才需要對errorHandler進行條件檢查。 – RomaH 2016-10-29 06:15:01

+1

@RomaH,除非你想匹配'/ smth /'而不是'/ smth/foo',在這種情況下它將歸入smthHandler但不會引發錯誤。 – Enrico 2017-02-25 18:45:54

0

也許我錯了,但我只是檢查來源:http://golang.org/src/pkg/net/http/server.go

好像指定自定義NOTFOUND()函數幾乎是不可能的:NotFoundHandler()返回稱爲NOTFOUND硬編碼功能()。

也許你應該就此提交一個問題。

作爲一種解決方法,您可以使用「/」處理程序,如果找不到其他處理程序(因爲它是最短的處理程序),則該處理程序是後備程序。所以,檢查頁面是否存在於該處理程序中並返回自定義404錯誤。

+0

我覺得一樣。我最終檢查了源代碼,發現NotFoundHandler函數返回一個硬編碼值,而不是允許您自定義該處理程序。我不明白爲什麼如此間接獲取NotFound函數,如果他們不讓你自定義這些類型的功能。 – 2017-01-24 14:49:55

0

以下是我選擇的方法。它基於一個代碼片段,我無法承認,因爲我失去了瀏覽器書籤。

示例代碼:(我把它放在我的主包)

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)); 
} 

敬請更正代碼,如果它是錯的,因爲我只是一個新手去。謝謝。

1

古代的線程,但我只是做了一些東西來攔截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) 
    } 
} 
相關問題