Gorilla/mux Golang:缓存静态文件

8
我有一个Go Web应用程序,它提供静态的HTML / JS / CSS文件和一些API端点。我发现我的HTML / JS / CSS没有被浏览器缓存。例如,每次重新加载页面时,它们都会被完全重新下载。
这是需要在服务器端进行配置更改吗?如何使用Go和Gorilla Mux完成此操作?
我正在使用Google App Engine,因此Nginx不可行。
下面是我的main.go代码:
package main

import (
    "associations"
    "html/template"
    "net/http"
    "log"
    "io/ioutil"

    "github.com/gorilla/mux"
    "github.com/rs/cors"
    "google.golang.org/appengine"
    "google.golang.org/appengine/mail"
)

var index = template.Must(template.ParseFiles(
    "dist/index.html",
))

func init() {
    r := mux.NewRouter()
    r.HandleFunc("/", homeHandler)  
    r.HandleFunc("/api/{tenant}/certificates", associations.GetCertificate).Methods("GET")
    r.HandleFunc("/api/{tenant}/requests", associations.PostRequest).Methods("POST")

    // handle static files
    r.PathPrefix("/static/").Handler(
        http.StripPrefix("/static/", http.FileServer(http.Dir("dist/static/"))))

    r.NotFoundHandler = http.HandlerFunc(homeHandler) // work around for SPA serving index.html

    handler := cors.Default().Handler(r)
    http.Handle("/", handler)
}

编辑:这里是@Topo提出的解决方案:

   // handle static files
        r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", 
CacheControlWrapper(http.FileServer(http.Dir("dist/static/")))))

    ....

func CacheControlWrapper(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Cache-Control", "max-age=2592000") // 30 days
        h.ServeHTTP(w, r)
    })
}
1个回答

12
告诉浏览器缓存文件,需要告诉它缓存的时间长度,否则用户将不会看到文件的新版本。只需在处理函数中设置 Cache-Control 头即可。
w.Header().Set("Cache-Control", "max-age=3600")

使用Etag标头告知浏览器文件是否有新版本,这也是一个好的做法。这样一来,您可以将文件缓存很长时间,并在新内容可用时立即向用户提供新内容:

etag := "some unique value"
w.Header().Set("Etag", etag)

每次文件更改时,您需要使用不同的etag值。浏览器会将其存储,并仅在etag与存储值不同时重新加载文件。您可以使用文件名+修改日期等内容作为etag:

var modTime time.Time
fi, err := fh.Stat()
if err == nil {
    modTime = fi.ModTime()
} else {
    modTime = time.Now()
}
etag := "\"" + file + modTime.String() + "\""
w.Header().Set("Etag", etag)

您可以阅读Mozilla文档的Cache-ControlEtag头部信息。

如果您想避免为静态文件编写自己的处理程序函数并继续使用http.FileServer,则需要在编写响应之前包装它,以设置头部信息。这里是一篇关于包装web处理程序的博客文章:Here


太棒了,谢谢。在我的情况下,我正在使用webpack,在每次构建后创建一个新的js文件,例如/static/js/app.3df99dd891ed2460b6bc.js,因此我认为对于我来说不需要etag部分,但是知道这一点很好。 - user1527312
只要 JavaScript 文件名更改,您就不需要它。如果您认为这是正确的答案,请不要忘记接受它。 - Topo
1
应该使用 if err == nil 而不是 != - Phani Rithvij

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接