如何解决静态资源的缓存问题

最近写了一个面向大众的导航站,初期一直在修改js和css,由于是托管到coding上的,浏览器的缓存问题是真的要命,自己倒是知道清理缓存,但其他人不知道啊,所以在网上查了下解决办法,特来总结一下

前言

浏览器的缓存机制其实是一个很好的优化机制,可以避免重复请求相同的资源,减轻服务器的压力,也可以加快用户的二次读取。但凡事都有优缺点,缓存的存在会导致css,js或者其他静态资源不能及时更新。有时修改了html,html一般不会读取缓存,但css和js读取了缓存,就会出现一些莫名其妙的问题,而到了用户那边,则会一脸懵逼。

浏览器的缓存原理

这个我也不太懂,就知道分为强制缓存和协商缓存。当二次打开网页时,浏览器会先对缓存发起http请求,只要请求的资源存在缓存并且该资源的请求头expirescache-control中存在缓存的标志,那就默认读取缓存,如果缓存失效但缓存依然存在,这时有会对服务器发出http请求,通过last-modifiedetag两个请求头验证是否存在协商缓存,存在协商缓存就让浏览器照样读取缓存。

当然,如果你资源已经不存在了或者明确禁止缓存,那浏览器也不可能使用缓存,这也是解决缓存问题的办法

强制缓存

强制缓存两个请求头,expirescache-control
expires不怎么用,是http1.0提出的一个表示资源过期时间的header
cache-control出现于 HTTP / 1.1,优先级高于 Expires,同样也可以表示资源过期时间
当然cache-control并没有这么简单,有很多值,但常用的基本就是下面5个值

  • public:所有内容都将被缓存(客户端和代理服务器都可缓存)
  • private:所有内容只有客户端可以缓存,Cache-Control的默认取值
  • no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
  • no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
  • max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效

    强制缓存是否生效,可以查看控制台的network选项,下面的size属性,一般就是from memory cache或者from disk cache,一个是从内存中加载缓存,一个是硬盘中加载缓存,区别就是内存要快些,一般先是读取硬盘中的缓存,要是你刷新一下,就从内存中读取,不然刷新的时候怎么那么快

协商缓存

当强制缓存失败,浏览器就请求服务器,如果服务器觉得用缓存没问题,资源又没有更新,那么,即使缓存设了到期时间,浏览器依然会读取,此时服务器返回304,如果资源更新了,就从服务器请求更新,返回200。如何判断资源是否更新,就是靠last-modifiedetag两个请求头,这里我就不多讲了

但是要注意,强制缓存要优先于协商缓存,所以嘛,就算你更新了,浏览器依旧会读取缓存,这也就是问题的由来,解决办法很简单,要么直接禁用缓存,告诉浏览器不准使用我的缓存,每次都从服务器加载。要么就是把文件名字改了,缓存名字对不上也就不会读取缓存了

解决办法

知乎上有个回答说的挺好

浏览器是好人(meta),浏览器有点坏(版本号),浏览器老子看你不爽了,我要“欺骗你”(md5)

meta缓存头设置为禁止缓存

在html的head标签中加入下面内容,就可以禁止浏览器读取缓存

1
<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作用于HTTP1.1
Pragma作用于HTTP1.0
Expires作用于`proxies

但这样浏览器在资源没修改的时候也不能加载缓存,十分影响体验

js、css加上版本号

当请求js、css的时候,给他们最后加上版本号,浏览器发现版本高了,就自然而然不会读取低版本的缓存了
版本号并不需要改变文件名,只需要在调用js、css的时候在最末尾加上?v=1.0即可,比如

1
2
custom.css?v=1.0
main.js?v=2.0

当然版本号也可以自动添加随机数,不过这样就违背了版本号的初衷了,这样同样浏览器在资源没修改的时候也不能加载缓存,影响体验
随机版本号的添加方法,使用一个随机函数即可,当然,这样就只能通过js中写js的调用语句,比如

1
document.write( " <script src='test.js?v= " + Math.random() + " '></s " + " cript> " )

或者是

1
var  js = document.createElement( " script " )js.src = " test.js" + "?v=" + Math.random()document.body.appendChild(js)

添加MD5

MD5相当于一个文件的身份证号,每个文件的MD5都不一样,同一个文件只要经过修改,MD5也不一样,所以我们可以通过MD5判断资源是否经过修改。当然这不可能让我们自己一个一个判断添加,肯定是服务器的事,我们这里不多说

补充

补充点清理浏览器缓存和解决CDN缓存的办法,你们不管遇到了什么问题。可以尝试清理缓存试试

快速清理浏览器缓存

可能有些人不知道如何快速清理浏览器缓存,这里我来介绍下,仅针对Chrome

  • Ctrl+F5 / Ctrl+Shift+R
    可能一般人知道F5是刷新,其实Ctrl+R也是刷新,而Ctrl+F5 / Ctrl+Shift+R就是不加载缓存并刷新
    当你鼠标左键长按刷新按钮,就会出现下列选项,作用也是一样的,最后一个是清除缓存再刷新
  • Ctrl+shift+Del
    清空浏览数据设置的快捷键,可以清除浏览数据呀,cookie呀,缓存呀,这是清除浏览器所有的缓存
  • 控制台禁止缓存
    这个隐藏在控制台network选项里的,对于开发人员很好用,默认禁止缓存

CDN的缓存

为了网站的加载速度快点,我把所有的静态资源放在了CDN上,由于是免费的CDN,清除缓存是不存在的了,当你修改个文件,可能要几个小时生效,这就很麻烦了

唯一的办法就是修改文件名

总结

还是引用知乎上的一句话

彻底禁止缓存,这个需求是错误的。缓存是浏览器的功能特性,又不是 Bug

没错,缓存很重要,彻底禁止缓存是不应该的,最好的办法就是添加版本号,当你修改了js、css文件,添加版本号是再自然而然不过的一件事了

参考链接

文章作者: ourongxing
文章链接: https://orxing.top/post/b52dc26d.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 OURONGXING

评论