dry69034 2017-11-14 11:50
浏览 82
已采纳

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

So I'm using a go server to serve up a single page web application.

This works for serving all the assets on the root route. All the CSS and HTML are served up correctly.

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.

But for a URL like http://myserverurl/myCustompage, it throws 404 if myCustompage is not a file in the build folder.

How do I make all routes for which a file does not exist serve index.html?

It is a single page web application and it will render the appropriate screen once the html and js are served. But it needs index.html to be served on routes for which there is no file.

How can this be done?

  • 写回答

1条回答 默认 最新

  • dongqiang1226 2017-11-14 13:08
    关注

    The handler returned by http.FileServer() does not support customization, it does not support providing a custom 404 page or action.

    What we may do is wrap the handler returned by http.FileServer(), and in our handler we may do whatever we want of course. 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.

    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.

    This is an example how this wrapper http.ResponseWriter may look like:

    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:

    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.

    And now put this in use, the main() function:

    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. 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. You can't run it there, save it to your local Go workspace and run it locally.

    Also check this related question: Log 404 on http.FileServer

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 用windows做服务的同志有吗
  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 一直显示正在等待HID—ISP