【前端开发日常 - 5】七牛CDN上的网页缓存问题及HTML禁止缓存
需求背景
前端开发的页面打包之后,为了提高访问的速度,往往会采用CDN(Content Delivery Network,内容分发网络)加速,通过将静态资源缓存到离用户很近的相同网络运营商的CDN节点上,不但能提升用户的访问速度,还能节省服务器的带宽消耗,降低负载。但是同样的,我们也不得不面临一些问题(以七牛CDN为例):
1、CDN缓存往往导致我们发布了新版网页,用户访问到的总是旧的页面;
2、大量刷新文件成本较高,且文件和目录的刷新有次数限制;
3、浏览器的本地缓存部分文件难以清除。
解决方案
阶段一 刷新关键文件缓存
在前端开发中,通过打包得到的静态资源往往不会经常变动,通常只有个别js文件和html文件改变,在发布新版本之后,可以登录七牛CDN,通过【CDN】-【刷新预取】填入需要刷新的文件进行刷新。
阶段二 为文件访问地址加上hash或时间戳
如果使用webpack打包,我们可以通过webpack配置hash或自定义版本,为每次打包生成不同的文件名和访问路径,从而减少发布到CDN之后需要刷新的文件数量。
阶段三 使用新的路径发布网页
1、发布网页到携带版本号的前缀下,如path/1.0.0/,下一次发布的时候则改为path/1.0.1/;
阶段四 去除文件缓存(进行中)
第三阶段的发布依旧会存在问题:
2、部分APP的webview缓存非常顽固(比如钉钉版的网页版),会将我们的整个网页缓存到本地,导致不能访问新版网页。
阶段四是目前准备做的一种方式,目标是去除部分HTML被用户的浏览器缓存。
去除HTML缓存
首先,我们需要去除HTML的缓存,我们可以采取通过meta标签去除缓存:
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
其中,Cache-Control 对 HTTP 1.1 使用,Pragma 对 HTTP 1.0 使用,Expires 对 proxies 使用。
修改CDD响应头的缓存设置
首先在七牛【CDN】 - 【域名管理】找到需要修改的域名,点击配置,再找到 【缓存配置】 - 【修改配置】,在里面配置不需要缓存的文件和目录。保存之后也记得去对需要清除缓存的文件进行刷新预取。
方案四还是在进行中,主要问题是七牛通过设置域名缓存之后,访问到的HTML文件依旧有一个很大的max-age,这将使得浏览器会长时间缓存文件,目前还在想办法处理中……
当然,通过设置整个 bucket 的配置参数是可以实现的,修改里面的 maxAge 选项,不过这将会对所有文件生效,并不可取。
核心代码
上面的各个阶段仅作为处理思路,下面来关注一下其它语言清除文件缓存的方式。
.htaccess (Apache)
<IfModule mod_headers.c>
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires 0
</IfModule>
Java Servlet
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
PHP
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
ASP
Response.addHeader "Cache-Control", "no-cache, no-store, must-revalidate"
Response.addHeader "Pragma", "no-cache"
Response.addHeader "Expires", "0"
ASP.NET
Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "0");
Ruby on Rails
response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
response.headers['Pragma'] = 'no-cache'
response.headers['Expires'] = '0'
Python on Flask
resp.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
resp.headers["Pragma"] = "no-cache"
resp.headers["Expires"] = "0"
Google Go
responseWriter.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
responseWriter.Header().Set("Pragma", "no-cache")
responseWriter.Header().Set("Expires", "0")
参考文档
Disable browser caching with meta HTML tags: http://cristian.sulea.net/blog/disable-browser-caching-with-meta-html-tags/