使用go静态文件服务器时如何自定义处理未找到的文件?

时间:2017-11-14 11:50:42

标签: go webserver go-server

所以我使用go服务器来提供单页Web应用程序。

这适用于提供根路由上的所有资产。所有CSS和HTML都正确提供。

fs := http.FileServer(http.Dir("build"))
http.Handle("/", fs)

因此,当网址为http://myserverurl/index.htmlhttp://myserverurl/styles.css时,它会提供相应的文件。

但对于http://myserverurl/myCustompage之类的网址,如果404不是构建文件夹中的文件,则会引发myCustompage

如何为文件不存在的所有路径提供index.html

这是一个单页面的Web应用程序,一旦提供html和js,它将呈现适当的屏幕。但它需要在没有文件的路由上提供index.html

如何做到这一点?

1 个答案:

答案 0 :(得分:4)

http.FileServer()返回的处理程序不支持自定义,它不支持提供自定义404页面或操作。

我们可以做的是包装http.FileServer()返回的处理程序,在我们的处理程序中,我们可以做任何我们想做的事情。在我们的包装器处理程序中,我们将调用文件服务器处理程序,如果这将发送404未找到的响应,我们将不会将其发送到客户端,而是用重定向响应替换它。

为了实现这一点,我们在包装器中创建了一个包装器http.ResponseWriter,我们将它传递给http.FileServer()返回的处理程序,在这个包装器响应编写器中我们可以检查状态代码,如果是404,我们可以采取行动将响应发送给客户,而是将重定向发送到/index.html

这是此包装器http.ResponseWriter的示例:

type NotFoundRedirectRespWr struct {
    http.ResponseWriter // We embed http.ResponseWriter
    status              int
}

func (w *NotFoundRedirectRespWr) WriteHeader(status int) {
    w.status = status // Store the status for our own use
    if status != http.StatusNotFound {
        w.ResponseWriter.WriteHeader(status)
    }
}

func (w *NotFoundRedirectRespWr) Write(p []byte) (int, error) {
    if w.status != http.StatusNotFound {
        return w.ResponseWriter.Write(p)
    }
    return len(p), nil // Lie that we successfully written it
}

包装http.FileServer()返回的处理程序可能如下所示:

func wrapHandler(h http.Handler) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        nfrw := &NotFoundRedirectRespWr{ResponseWriter: w}
        h.ServeHTTP(nfrw, r)
        if nfrw.status == 404 {
            log.Printf("Redirecting %s to index.html.", r.RequestURI)
            http.Redirect(w, r, "/index.html", http.StatusFound)
        }
    }
}

请注意,我使用http.StatusFound重定向状态代码而不是http.StatusMovedPermanently,因为后者可能会被浏览器缓存,因此如果稍后创建具有该名称的文件,浏览器将不会请求但是立即显示index.html

现在正在使用main()函数:

func main() {
    fs := wrapHandler(http.FileServer(http.Dir(".")))
    http.HandleFunc("/", fs)
    panic(http.ListenAndServe(":8080", nil))
}

尝试查询不存在的文件,我们会在日志中看到:

2017/11/14 14:10:21 Redirecting /a.txt3 to /index.html.
2017/11/14 14:10:21 Redirecting /favicon.ico to /index.html.

请注意,我们的自定义处理程序(良好行为)也将请求重定向到/favico.icoindex.html,因为我的文件系统中没有favico.ico文件。如果您没有它,可能需要将其添加为例外。

Go Playground上提供了完整的示例。您无法在那里运行它,将其保存到本地Go工作区并在本地运行。

另请查看以下相关问题:Log 404 on http.FileServer