显示带标准 http 包的自定义404错误页面

假设我们有:

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

当用户尝试错误的 URL 时,会看到一个简单的“404页面未找到”。我怎样才能返回一个自定义页面的情况?

关于大猩猩的最新消息

接受的答案是确定的那些使用纯净的网络/http 包。

如果你使用 gorilla/mux,你应该使用这样的东西:

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

并根据需要实现 func notFound(w http.ResponseWriter, r *http.Request)

64452 次浏览

也许我错了,但我刚查了资料来源: http://golang.org/src/pkg/net/http/server.go

似乎指定自定义 NotFound ()函数是不可能的: NotFoundHandler ()返回一个名为 NotFound ()的硬编码函数。

也许,你应该就此提交一期。

作为一种解决方案,您可以使用您的“/”处理程序,如果没有找到其他处理程序(因为它是最短的处理程序) ,这是一种备份。因此,检查该处理程序中是否存在页面并返回自定义的404错误。

您只需要创建自己的 notFind 处理程序,并将其注册到 HandleFunc 中,以获得您不需要处理的路径。

如果希望对路由逻辑进行最大程度的控制,则需要使用自定义服务器和自定义处理程序类型。

这允许您实现比 HandleFunc 允许的更复杂的路由逻辑。

我通常这样做:

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

以下是我选择的方法。它是基于一个代码片段,我不能承认,因为我丢失了浏览器书签。

示例代码: (我将其放在主包中)

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,你可能希望将主要功能替换为:

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

我认为干净的方法是这样的:

func main() {


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


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

如果地址不是/calator 或/history,那么它将处理 notFoundHandler 函数。

你可以简单地使用:

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