Go语言 用标准http包显示自定义404错误页面

s3fp2yjn  于 2023-04-27  发布在  Go
关注(0)|答案(9)|浏览(357)

假设我们有:

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

当用户尝试错误的URL时,会看到一个普通的“404页面未找到”。我如何为这种情况返回一个自定义页面?

关于gorilla/mux的更新

对于那些使用纯net/http包的人来说,接受的答案是可以的。
如果你使用gorilla/mux,你应该使用这样的代码:

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

并按照您的需要实现func notFound(w http.ResponseWriter, r *http.Request)

9njqaruj

9njqaruj1#

我通常这样做:

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错误,在其中记录有用的信息并向自己发送电子邮件。

dauxcl2d

dauxcl2d2#

下面是我选择的方法。它基于一个代码片段,因为我丢失了浏览器书签,所以我无法确认。
示例代码:(我把它放在我的主包里)

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消息。
如果您使用的是Gorilla Mux,您可能希望将main函数替换为:

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

如果代码有误,请大家指正,因为我是围棋新手,谢谢。

mpbci0fu

mpbci0fu3#

古老的线程,但我只是做了一些拦截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)
    }
}
jexiocij

jexiocij4#

我认为最简单的方法是这样的:

func main() {

http.HandleFunc("/calculator", calculatorHandler)
http.HandleFunc("/history", historyHandler)
http.HandleFunc("/", notFoundHandler)

log.Fatal(http.ListenAndServe(":80", nil))
}

如果地址不是/calulator或/history,则它处理notFoundHandler函数。

z9smfwbn

z9smfwbn5#

也许我错了,但我刚查了资料来源:http://golang.org/src/pkg/net/http/server.go
似乎指定自定义NotFound()函数几乎是不可能的:NotFoundHandler()返回一个名为NotFound()的硬编码函数。
也许你应该就此提出一个问题。
作为一种变通方法,您可以使用“/”处理程序,如果没有找到其他处理程序(因为它是最短的一个),这是一个回退。因此,检查该处理程序中是否存在页面并返回自定义404错误。

chy5wohz

chy5wohz6#

您只需要创建自己的notFound处理程序,并将其注册到HandleFunc,以获取您不处理的路径。
如果您希望对路由逻辑进行最大程度的控制,则需要使用自己的自定义服务器和自定义处理程序类型。

  • http://golang.org/pkg/net/http/#Handler
  • http://golang.org/pkg/net/http/#Server

这使您可以实现比HandleFunc更复杂的路由逻辑。

7vux5j2d

7vux5j2d7#

你可以定义

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

当访问没有找到资源时,它将执行到http.HandleFunc(“/",xxx)

webghufk

webghufk8#

简而言之,只需检查r.URL.Path是否与您希望找到的URL匹配,例如通过循环遍历一个页面数组。
现在,我在一个名为drawPage的函数中这样做:

is404 := true // assume the worst

// start loop through a data structure of all my pages
    if (r.URL.Path == data.Options[i].URL) { is404 = false }
// end loop

if is404 { // failed our test
    w.WriteHeader(404)
    w.Write([]byte(`404 not found`))
    return 
} 

// draw the page we found

Last part is taken from @许晨峰

2ekbmq32

2ekbmq329#

您可以简单地使用类似于:

func Handle404(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "404 error\n")
}

func main(){
   http.HandleFunc("/", routes.Handle404)
}

如果你需要一个标准的,只要写:

func main(){
   http.HandleFunc("/", http.NotFound)
}

你会得到:

404 page not found

相关问题