Rails 7+Heroku+Fastly环境下如何禁止缓存PWA的sw.js文件?
Rails 7 + Heroku + Fastly 环境下Service Worker(sw.js)无缓存部署最佳实践
核心需求
要确保sw.js文件直接从Heroku后端获取,不被Fastly CDN缓存,同时浏览器也不会缓存该文件,保证Service Worker能实时更新。
方案一:修改Fastly VCL规则(绕过CDN缓存)
针对你提供的默认vcl_recv子程序,添加判断逻辑,当请求路径为/sw.js时,直接跳过CDN缓存,回源到Heroku后端。
修改后的vcl_recv代码:
#--FASTLY RECV BEGIN if (req.restarts == 0) { if (!req.http.X-Timer) { set req.http.X-Timer = "S" time.start.sec "." time.start.usec_frac; } set req.http.X-Timer = req.http.X-Timer ",VS0"; } set req.http.Fastly-Orig-Host = req.http.host; set req.http.host = "my-app.herokuapp.com"; declare local var.fastly_req_do_shield BOOL; set var.fastly_req_do_shield = (req.restarts == 0); # default conditions set req.backend = F_kinscape_production_herokuapp_com__Heroku_; # end default conditions #--FASTLY RECV END # 新增:针对sw.js跳过CDN缓存,直接回源 if (req.url == "/sw.js") { return(pass); } if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") { return(pass); } return(lookup); }
代码说明
新增的if (req.url == "/sw.js") { return(pass); }会让Fastly直接将请求转发到Heroku后端,不经过CDN缓存层,确保每次请求都获取最新的sw.js。
方案二:设置浏览器端无缓存头
即使CDN回源,仍需确保浏览器不会缓存sw.js,可通过两种方式实现:
方式1:在Fastly的vcl_deliver子程序中添加缓存控制头
在Fastly的VCL配置中添加vcl_deliver规则,对sw.js返回强缓存禁止的响应头:
if (req.url == "/sw.js") { set resp.http.Cache-Control = "no-cache, no-store, must-revalidate"; set resp.http.Pragma = "no-cache"; set resp.http.Expires = "0"; } }
方式2:通过Rails配置设置静态文件头
在Rails项目的config/initializers/assets.rb中添加配置,让sw.js返回正确的缓存头:
Rails.application.config.public_file_server.headers = { "Cache-Control" => "no-cache, no-store, must-revalidate", "Pragma" => "no-cache", "Expires" => "0" }
如果只想针对sw.js单独配置,也可以将sw.js移到app/assets/javascripts,通过控制器返回并设置响应头,但静态文件直接配置更简洁。
补充:默认vcl_recv子程序中文翻译与说明
#--FASTLY RECV 开始 # 如果是首次请求(未重启) if (req.restarts == 0) { # 初始化X-Timer头,记录请求开始时间 if (!req.http.X-Timer) { set req.http.X-Timer = "S" time.start.sec "." time.start.usec_frac; } # 添加VS0标记到X-Timer头 set req.http.X-Timer = req.http.X-Timer ",VS0"; } # 保存原始请求的Host头 set req.http.Fastly-Orig-Host = req.http.host; # 将请求Host设置为Heroku应用的域名 set req.http.host = "my-app.herokuapp.com"; # 声明本地变量,标记是否需要使用屏蔽层(Shield) declare local var.fastly_req_do_shield BOOL; # 仅首次请求时使用屏蔽层 set var.fastly_req_do_shield = (req.restarts == 0); # 默认后端配置 set req.backend = F_kinscape_production_herokuapp_com__Heroku_; # 结束默认条件 #--FASTLY RECV 结束 # 非HEAD/GET/FASTLYPURGE请求直接回源 if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") { return(pass); } # 其他请求进入CDN缓存查找流程 return(lookup); }
内容的提问来源于stack exchange,提问作者Meltemi
相关产品推荐
相关产品推荐

