我有第三方网站使用的脚本:/assets/script.js
。出于显而易见的原因,我不能要求他们在每次部署时更改链接以指向脚本的最新指纹版本。我遇到了一些缓存问题,用户仍然会看到/script.js
的旧版本。有没有办法让缓存直接消失script.js
而不是script-9dc5afea3571ba2a883a72b0da0bb623.js
?
更多信息:Passenger + Nginx上的Rails。寻找提供script.js
文件的方法,如果是指纹打印文件并在每次部署时使缓存无效。
我考虑过根据部署git修订添加ETag,但不知道如何做到这一点。 Nginx没有内置的ETags支持。有不受支持的旧第三方模块可以执行此操作。我可以使用add_header Etag="something"
,但是如何在那里添加git版本。
还有其他想法和选择吗?
谢谢!
答案 0 :(得分:9)
如果您的脚本的名称是公共接口的一部分,那么您需要明确地开始对此脚本进行版本控制,并为旧客户端保留旧版本。
e.g。 /assets/script.1.0.js,/assets/script.1.1.js等
关键部分是你需要保持旧的,并且代码没有明确改变名称而改变。 Rails资产管道不能为您执行此操作,因为通常只有最新版本的脚本保持最新。
与所有公共接口一样,您需要花费更多时间来管理此过程,而不是仅使用内部脚本。
答案 1 :(得分:3)
我建议使用ETag。 在您的回复中添加ETag标头 http://en.wikipedia.org/wiki/HTTP_ETag
为每个版本的脚本将ETag标头设置为不同的唯一字符串。 这将确保浏览器在部署新版本时获得新版本的脚本。
答案 2 :(得分:3)
nginx能够生成最新版本的etags:http://nginx.org/en/docs/http/ngx_http_core_module.html#etag
我在这里也看到了以下配置:https://serverfault.com/questions/426260/nginx-cache-control
location /static {
alias /opt/static/blog/;
access_log off;
etags on;
etag_hash on;
etag_hash_method md5;
expires 1d;
add_header Pragma "public";
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
答案 3 :(得分:1)
根据ETag建议,你可能会发现这个宝石很有用:bust_rails_etags。它允许您在每个部署中设置一个用于生成ETag的密钥,这样,每次部署应用程序时,您的ETag都会发生变化(因此缓存的脚本将失效)。作者使用Heroku版本号的示例作为在每次部署时更改的密钥。
答案 4 :(得分:1)
我用于更新资产的是:
config.assets.version
中的增量config/application.rb
#Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.1'
bundle exec rake assets:precompile RAILS_ENV=production RAILS_GROUPS=assets
应用重启,空网页服务器缓存(如果有)
答案 5 :(得分:1)
您需要第三方网站的非指纹资产网址。 例如:assets / public_api.js
有插件或宝石从指纹识别中排除指定的资产。但是,rails已经以一种同样创建非指纹文件的方式更改了预编译过程。因此这不是问题。更多信息here.
如果资产没有指纹识别,如何确保客户端正在加载最新部署的脚本?
我会建议解决方案youTube uses to expose their API。基本上所有资产/ public_api.js都会这样做,它会在dom中注入另一个脚本标记。注入一个加载实际的API代码。现在您的assets / public_api.js变为assets / public_api.js.erb,看起来像这样:
var tag = document.createElement('script');
tag.src = "<%=asset_path('/assets/javascripts/acctual_api')%>";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
请注意 tag.src 如何设置为当前指纹路径到/ assets / javascripts / acctual_api。这样,您的用户将始终获得最新编译的acctual_api脚本。
如何更新资产/ public_api.js的ETAG?
我想您使用Capistrano或类似的基于配方的部署解决方案。也许您可以添加一个部署步骤,在重新启动之前更新服务器配置文件。它应该更新:
add_header Etag="update_me_on_deploy"
请注意,即使采用这种方法,您仍应使用版本化(assets / public_api.0.js)公共脚本。
答案 6 :(得分:1)
如果您使用的是Capistrano,则可以编写一个任务,在您的资产进行预编译后,将脚本从Public / assets复制到Public中的另一个目录(即Public / scripts)。
答案 7 :(得分:1)
您可以删除文件的指纹:
asset_path('script.js', :digest => false)
希望有所帮助
如果您愿意,也可以使用此gem:https://github.com/spohlenz/digestion
但是:Rails资产管道现在可以使用和不使用摘要编译资产文件。
因此,在生成资产后,通常会将script.js?xxxxx和script.js放入public / assets文件夹中。