因此,我正在使用Go服务器来提供单个页面的Web应用程序。
这适用于服务根路由上的所有资产。所有CSS和HTML均已正确提供。
fs := http.FileServer(http.Dir("build")) http.Handle("/", fs)
因此,当URL为http://myserverurl/index.html或时http://myserverurl/styles.css,它将提供相应的文件。
http://myserverurl/index.html
http://myserverurl/styles.css
但是对于类似的URL http://myserverurl/myCustompage,404如果myCustompage不是build文件夹中的文件,它将抛出。
http://myserverurl/myCustompage
404
myCustompage
如何使不存在文件的所有路由服务index.html?
index.html
它是一个单页Web应用程序,一旦提供html和js,它将呈现适当的屏幕。但它需要index.html在没有文件的路由上提供。
如何才能做到这一点?
返回的处理程序http.FileServer()不支持自定义,它不支持提供自定义404页面或操作。
http.FileServer()
我们可以做的是包装由返回的处理程序http.FileServer(),并且在我们的处理程序中,我们当然可以做我们想做的任何事情。在包装器处理程序中,我们将调用文件服务器处理程序,如果该处理程序将发送404未找到的响应,则不会将其发送给客户端,而是将其替换为重定向响应。
为此,我们在包装器中创建了一个包装器http.ResponseWriter,该包装器将传递给由返回的处理程序http.FileServer(),在该包装器响应编写器中,我们可以检查状态代码,如果是404,我们可以采取行动 不 将响应发送给客户端,而是将重定向发送到/index.html。
http.ResponseWriter
/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立即显示。
http.StatusFound
http.StatusMovedPermanently
现在使用该main()功能:
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我的文件系统中没有文件。如果您也没有,可以将其添加为例外。
/favico.ico
favico.ico
完整的示例可在GoPlayground上找到。您无法在此处运行它,将其保存到本地Go工作区中并在本地运行。