我正在寻找一种在版本更改时使缓存的静态内容无效的方法。最好使用commit id来使其无效。无论如何在狂欢框架中做到这一点?
我更愿意,如果它是自动的,但我可以忍受每次更新它,如果它是我必须编辑的一个地方。
我当前的策略是将静态内容路由的名称更改为包含版本,但这需要进行多处更改。在感觉不自然的地方,例如在路由文件中。
答案 0 :(得分:1)
您可以通过配置变量和拦截方法手动完成。
在您的controllers文件夹中创建此文件:
package controllers
import (
"github.com/revel/revel"
)
// interceptor method, called before every request.
// Sets a template variable to the resourceVersion read from app.conf
func SetVersion(c *revel.Controller) revel.Result {
c.RenderArgs["resourceVersion"] = revel.Config.StringDefault("resourceVersion", "1")
return nil
}
在init()方法中,添加以下行:
revel.InterceptMethod(controllers.SetVersion, revel.BEFORE)
在模板中,您要使用资源版本:
<link rel="stylesheet" type="text/css" href="/public/css/style.css?{{.resourceVersion}}">
最后,你将更新它的地方 - 在dev部分上方添加这一行以应用于dev和prod,或者在每个中都有不同的一行,无论什么都适合。
resourceVersion=20150716
我想你可以创建一个脚本作为构建和发布过程的一部分,自动编辑这个配置变量。
答案 1 :(得分:0)
我做了Colin Nicholson建议的事情,但我还创建了一个名为staticversionbasedcacheinvalidator的控制器并将其放在controller文件夹中。你可以在下面找到它。它允许您忽略请求字符串的第一部分,允许您使用公用文件夹的通配符路径。例如,我使用此路由配置行
GET /public/*filepath StaticVersionbasedCacheInvalidator.Serve("public")
然后我在我的路线中添加了{{.resourceVersion}},而不是作为查询参数。
package controllers
import (
"github.com/revel/revel"
"os"
fpath "path/filepath"
"strings"
"syscall"
)
type StaticVersionbasedCacheInvalidator struct {
*revel.Controller
}
// This method handles requests for files. The supplied prefix may be absolute
// or relative. If the prefix is relative it is assumed to be relative to the
// application directory. The filepath may either be just a file or an
// additional filepath to search for the given file. This response may return
// the following responses in the event of an error or invalid request;
// 403(Forbidden): If the prefix filepath combination results in a directory.
// 404(Not found): If the prefix and filepath combination results in a non-existent file.
// 500(Internal Server Error): There are a few edge cases that would likely indicate some configuration error outside of revel.
//
// Note that when defining routes in routes/conf the parameters must not have
// spaces around the comma.
// Bad: StaticVersionbasedCacheInvalidator.Serve("public/img", "favicon.png")
// Good: StaticVersionbasedCacheInvalidator.Serve("public/img","favicon.png")
//
// Examples:
// Serving a directory
// Route (conf/routes):
// GET /public/{<.*>filepath} StaticVersionbasedCacheInvalidator.Serve("public")
// Request:
// public/js/sessvars.js
// Calls
// StaticVersionbasedCacheInvalidator.Serve("public","js/sessvars.js")
//
// Serving a file
// Route (conf/routes):
// GET /favicon.ico StaticVersionbasedCacheInvalidator.Serve("public/img","favicon.png")
// Request:
// favicon.ico
// Calls:
// StaticVersionbasedCacheInvalidator.Serve("public/img", "favicon.png")
func (c StaticVersionbasedCacheInvalidator) Serve(prefix, filepath string) revel.Result {
firstSplice := strings.Index(filepath,"/")
if(firstSplice != -1) {
filepath = filepath[firstSplice:len(filepath)];
}
// Fix for #503.
prefix = c.Params.Fixed.Get("prefix")
if prefix == "" {
return c.NotFound("")
}
return serve(c, prefix, filepath)
}
// This method allows modules to serve binary files. The parameters are the same
// as StaticVersionbasedCacheInvalidator.Serve with the additional module name pre-pended to the list of
// arguments.
func (c StaticVersionbasedCacheInvalidator) ServeModule(moduleName, prefix, filepath string) revel.Result {
// Fix for #503.
prefix = c.Params.Fixed.Get("prefix")
if prefix == "" {
return c.NotFound("")
}
var basePath string
for _, module := range revel.Modules {
if module.Name == moduleName {
basePath = module.Path
}
}
absPath := fpath.Join(basePath, fpath.FromSlash(prefix))
return serve(c, absPath, filepath)
}
// This method allows StaticVersionbasedCacheInvalidator serving of application files in a verified manner.
func serve(c StaticVersionbasedCacheInvalidator, prefix, filepath string) revel.Result {
var basePath string
if !fpath.IsAbs(prefix) {
basePath = revel.BasePath
}
basePathPrefix := fpath.Join(basePath, fpath.FromSlash(prefix))
fname := fpath.Join(basePathPrefix, fpath.FromSlash(filepath))
// Verify the request file path is within the application's scope of access
if !strings.HasPrefix(fname, basePathPrefix) {
revel.WARN.Printf("Attempted to read file outside of base path: %s", fname)
return c.NotFound("")
}
// Verify file path is accessible
finfo, err := os.Stat(fname)
if err != nil {
if os.IsNotExist(err) || err.(*os.PathError).Err == syscall.ENOTDIR {
revel.WARN.Printf("File not found (%s): %s ", fname, err)
return c.NotFound("File not found")
}
revel.ERROR.Printf("Error trying to get fileinfo for '%s': %s", fname, err)
return c.RenderError(err)
}
// Disallow directory listing
if finfo.Mode().IsDir() {
revel.WARN.Printf("Attempted directory listing of %s", fname)
return c.Forbidden("Directory listing not allowed")
}
// Open request file path
file, err := os.Open(fname)
if err != nil {
if os.IsNotExist(err) {
revel.WARN.Printf("File not found (%s): %s ", fname, err)
return c.NotFound("File not found")
}
revel.ERROR.Printf("Error opening '%s': %s", fname, err)
return c.RenderError(err)
}
return c.RenderFile(file, revel.Inline)
}