使用go静态文件服务器时如何自定义处理未找到的文件?
How to custom handle a file not being found when using go static file server?
所以我正在使用 go 服务器来提供单页 Web 应用程序。
这适用于为根路由上的所有资产提供服务。所有 CSS 和 HTML 均已正确提供。
fs := http.FileServer(http.Dir("build"))
http.Handle("/", fs)
所以当URL是http://myserverurl/index.html
或http://myserverurl/styles.css
时,它提供相应的文件。
但是对于像 http://myserverurl/myCustompage
这样的 URL,如果 myCustompage
不是构建文件夹中的文件,它会抛出 404
。
如何使文件不存在的所有路由服务 index.html
?
它是一个单页 Web 应用程序,一旦 html 和 js 被提供,它将呈现适当的屏幕。但它需要 index.html
在没有文件的路由上提供服务。
如何做到这一点?
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.ico
到 index.html
,因为我的文件系统中没有 favico.ico
文件。如果您也没有它,您可能想将其添加为例外。
完整示例可在 Go Playground 上找到。你不能在那里运行它,将它保存到你本地的 Go 工作区并在本地运行它。
同时检查这个相关问题:
所以我正在使用 go 服务器来提供单页 Web 应用程序。
这适用于为根路由上的所有资产提供服务。所有 CSS 和 HTML 均已正确提供。
fs := http.FileServer(http.Dir("build"))
http.Handle("/", fs)
所以当URL是http://myserverurl/index.html
或http://myserverurl/styles.css
时,它提供相应的文件。
但是对于像 http://myserverurl/myCustompage
这样的 URL,如果 myCustompage
不是构建文件夹中的文件,它会抛出 404
。
如何使文件不存在的所有路由服务 index.html
?
它是一个单页 Web 应用程序,一旦 html 和 js 被提供,它将呈现适当的屏幕。但它需要 index.html
在没有文件的路由上提供服务。
如何做到这一点?
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.ico
到 index.html
,因为我的文件系统中没有 favico.ico
文件。如果您也没有它,您可能想将其添加为例外。
完整示例可在 Go Playground 上找到。你不能在那里运行它,将它保存到你本地的 Go 工作区并在本地运行它。
同时检查这个相关问题: