简体   繁体   English

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

[英]How to custom handle a file not being found when using go static file server?

So I'm using a go server to serve up a single page web application. 所以我使用go服务器来提供单页Web应用程序。

This works for serving all the assets on the root route. 这适用于提供根路由上的所有资产。 All the CSS and HTML are served up correctly. 所有CSS和HTML都正确提供。

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

So when the URL is http://myserverurl/index.html or http://myserverurl/styles.css , it serves the corresponding file. 因此,当URL为http://myserverurl/index.htmlhttp://myserverurl/styles.css ,它会提供相应的文件。

But for a URL like http://myserverurl/myCustompage , it throws 404 if myCustompage is not a file in the build folder. 但对于像http://myserverurl/myCustompage这样的URL,如果myCustompage不是build文件夹中的文件,则会抛出404

How do I make all routes for which a file does not exist serve index.html ? 如何使文件不存在的所有路径都提供index.html

It is a single page web application and it will render the appropriate screen once the html and js are served. 它是单页面Web应用程序,一旦提供html和js,它将呈现适当的屏幕。 But it needs index.html to be served on routes for which there is no file. 但它需要index.html在没有文件的路由上提供服务。

How can this be done? 如何才能做到这一点?

The handler returned by http.FileServer() does not support customization, it does not support providing a custom 404 page or action. http.FileServer()返回的处理程序不支持自定义,它不支持提供自定义404页面或操作。

What we may do is wrap the handler returned by http.FileServer() , and in our handler we may do whatever we want of course. 我们可能做的是包装http.FileServer()返回的处理程序,在我们的处理程序中,我们可以做任何我们想做的事情。 In our wrapper handler we will call the file server handler, and if that would send a 404 not found response, we won't send it to the client but replace it with a redirect response. 在我们的包装器处理程序中,我们将调用文件服务器处理程序,如果这将发送404未找到的响应,我们将不会将其发送到客户端,而是用重定向响应替换它。

To achieve that, in our wrapper we create a wrapper http.ResponseWriter which we will pass to the handler returned by http.FileServer() , and in this wrapper response writer we may inspect the status code, and if it's 404 , we may act to not send the response to the client, but instead send a redirect to /index.html . 为了实现这一点,我们在包装器中创建了一个包装器http.ResponseWriter ,我们将它传递给http.FileServer()返回的处理程序,在这个包装器响应编写器中我们可以检查状态代码,如果它是404 ,我们可以采取行动将响应发送给客户端,而是将重定向发送到/index.html

This is an example how this wrapper http.ResponseWriter may look like: 这是一个如何包装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
}

And wrapping the handler returned by http.FileServer() may look like this: 包装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)
        }
    }
}

Note that I used http.StatusFound redirect status code instead of http.StatusMovedPermanently as the latter may be cached by browsers, and so if a file with that name is created later, the browser would not request it but display index.html immediately. 请注意,我使用http.StatusFound重定向状态代码而不是http.StatusMovedPermanently因为后者可能会被浏览器缓存,因此如果稍后创建具有该名称的文件,浏览器将不会请求它,而是立即显示index.html

And now put this in use, the main() function: 现在把它放在使用中, main()函数:

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

Attempting to query a non-existing file, we'll see this in the log: 尝试查询不存在的文件,我们将在日志中看到:

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

Note that our custom handler (being well-behaviour) also redirected the request to /favico.ico to index.html because I do not have a favico.ico file in my file system. 请注意,我们的自定义处理程序(良好行为)也将请求重定向到/favico.icoindex.html因为我的文件系统中没有favico.ico文件。 You may want to add this as an exception if you don't have it either. 如果您没有它,您可能希望将其添加为例外。

The full example is available on the Go Playground . Go Playground上提供了完整的示例。 You can't run it there, save it to your local Go workspace and run it locally. 您无法在那里运行它,将其保存到本地Go工作区并在本地运行它。

Also check this related question: Log 404 on http.FileServer 另请检查此相关问题: 在http.FileServer上记录404

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM