Rails 3.1中的第三方脚本缓存

3rd Party Script Caching in Rails 3.1

本文关键字:第三方 脚本 缓存 Rails      更新时间:2023-09-26

我有一个脚本第三方网站正在使用:/assets/script.js。由于显而易见的原因,我不能要求他们在每次部署时更改链接,以指向脚本的最新指纹版本。我有一些缓存问题,用户仍然看到旧版本的/script.js。是否有办法使缓存直接消失为script.js而不是script-9dc5afea3571ba2a883a72b0da0bb623.js ?

更多信息: Rails on Passenger + Nginx。寻找方法来提供script.js文件,而不是指纹文件,并在每次部署时使缓存无效。

我想添加ETags基于部署git修订,但不知道如何做到这一点。Nginx没有内置ETags支持。有一些不受支持的旧第三方模块可以做到这一点。我可以使用add_header Etag="something",但是我如何在那里添加git版本呢?

还有其他的想法和选择吗?

谢谢!

如果你有一个脚本的名字是你的公共接口的一部分,那么你需要开始显式地控制这个脚本的版本,并为旧的客户端保留旧的版本。

。/assets/script.1.0.js、/assets/script. 1.1.1 .js等

关键的部分是你需要保留旧的,并且代码不会在没有显式更改名称的情况下改变。Rails资产管道不能为您做这些,因为通常只有最新版本的脚本保持最新。

与所有公共接口一样,您需要花费更多的时间来管理这个过程,而不是管理一个内部脚本。

我建议使用ETag。在响应中添加ETag标头http://en.wikipedia.org/wiki/HTTP_ETag

为脚本的每个版本设置ETag头为不同的、唯一的字符串。这将确保浏览器在部署新版本时获得新版本的脚本。

nginx可以在最新版本中生成标签: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";
}

根据ETag的建议,您可能会发现这个gem很有用:bust_rails_etags。它允许你在每次部署时设置一个键,用于生成ETags,这样,你的ETags会在每次部署时发生变化(因此缓存的脚本将无效)。作者使用Heroku版本号的例子作为每次部署时更改的键。

我用来更新资产的是:

  1. config/application.rb中增加config.assets.version

    #Version of your assets, change this if you want to expire all your assets
    config.assets.version = '1.1'
    
  2. bundle exec rake assets:precompile RAILS_ENV=production RAILS_GROUPS=assets

  3. App重启,清空缓存

如果您正在使用Capistrano,您可以编写一个任务,在您的资产预编译后,将脚本从Public/assets复制到Public中的另一个目录(即Public/scripts)。

你可以删除文件的指纹:

asset_path('script.js', :digest => false)

希望能有所帮助

或者你也可以使用这个gem: https://github.com/spohlenz/digestion

但是:Rails资产管道现在可以编译带有和不带有摘要的资产文件。

所以在你生成你的资产通常你得到script.js?XXXXX和script.js放到你的公共/assets文件夹中。

您希望第三方网站的非指纹资产url 例如:assets/public_api.js

有一些插件或宝石从指纹识别中排除了特定的资产。然而,rails改变了预编译过程,它也创建了非指纹文件。因此这不是问题。更多信息在这里。

如何确保您的客户端正在加载最新部署的脚本,当资产没有指纹?

我建议youTube使用的解决方案来公开他们的API。基本上所有你的assets/public_api.js做的,它注入另一个脚本标签到dom。注入的那个会加载实际的API代码。现在你的assets/public_api.js变成了assets/public_api.js。动词,看起来像这样:
var tag = document.createElement('script');
tag.src = "<%=asset_path('/assets/javascripts/acctual_api')%>";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

请注意标签。src被设置为当前指纹路径到/assets/javascripts/acctual_api。这样您的用户将始终获得最新编译的acctual_api脚本。

如何为assets/public_api.js更新ETAG ?

我假设您使用Capistrano或类似的基于配方的部署解决方案。也许您可以添加一个部署步骤,在服务器重新启动之前更新服务器配置文件。它应该只是更新:

add_header Etag="update_me_on_deploy"

请注意,即使使用这种方法,您仍然应该使用版本化的(assets/public_api.0.js)公共脚本。