статические файлы кеша gorilla/mux golang

У меня есть веб-приложение, которое обслуживает статические файлы 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)
    })
}

person user1527312    schedule 20.02.2018    source источник


Ответы (1)


Чтобы указать браузеру кэшировать ваши файлы, вам нужно сообщить ему, как долго, иначе пользователь никогда не увидит более новые версии файла.

Для этого просто установите заголовок 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-Control и теги Etag.

Если вы хотите избежать написания собственной функции-обработчика для статических файлов и вместо этого продолжать использовать http.FileServer, вам нужно будет обернуть ее в обработчик, который устанавливает заголовки перед записью ответа. Вот сообщение в блоге об обертывании веб-обработчиков.

person Topo    schedule 20.02.2018
comment
круто, спасибо. В моем случае я использую webpack, который создает новый файл js, такой как /static/js/app.3df99dd891ed2460b6bc.js, после каждой сборки, поэтому я не думаю, что мне нужна часть etag, но полезно знать - person user1527312; 20.02.2018
comment
@user1527312 user1527312 Пока имя файла js меняется, с вами все будет в порядке. Не забудьте принять ответ, если считаете его правильным. - person Topo; 20.02.2018
comment
должно быть если err == nil вместо != - person Phani Rithvij; 03.12.2020