Rails中的第三方脚本缓存3.1

时间:2012-12-23 22:15:56

标签: javascript ruby-on-rails ruby ruby-on-rails-3 nginx

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

更多信息:Passenger + Nginx上的Rails。寻找提供script.js文件的方法,如果是指纹打印文件并在每次部署时使缓存无效。

我考虑过根据部署git修订添加ETag,但不知道如何做到这一点。 Nginx没有内置的ETags支持。有不受支持的旧第三方模块可以执行此操作。我可以使用add_header Etag="something",但是如何在那里添加git版本。

还有其他想法和选择吗?

谢谢!

8 个答案:

答案 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)

我用于更新资产的是:

  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'
    
  2. bundle exec rake assets:precompile RAILS_ENV=production RAILS_GROUPS=assets

  3. 应用重启,空网页服务器缓存(如果有)

答案 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文件夹中。