本文首发于我的个人博客 https:// orxing.top ,欢迎来访
最近写了一个面向大众的导航站,初期一直在修改js和css,由于是托管到coding上的,浏览器的缓存问题是真的要命,自己倒是知道清理缓存,但其他人不知道啊,所以在网上查了下解决办法,特来总结一下
前言
浏览器的缓存机制其实是一个很好的优化机制,可以避免重复请求相同的资源,减轻服务器的压力,也可以加快用户的二次读取。但凡事都有优缺点,缓存的存在会导致css,js或者其他静态资源不能及时更新。有时修改了html,html一般不会读取缓存,但css和js读取了缓存,就会出现一些莫名其妙的问题,而到了用户那边,则会一脸懵逼。
浏览器的缓存原理
这个我也不太懂,就知道分为强制缓存和协商缓存。当二次打开网页时,浏览器会先对缓存发起http请求,只要请求的资源存在缓存并且该资源的请求头
expires
和
cache-control
中存在缓存的标志,那就默认读取缓存,如果缓存失效但缓存依然存在,这时有会对服务器发出http请求,通过
last-modified
和
etag
两个请求头验证是否存在协商缓存,存在协商缓存就让浏览器照样读取缓存。
当然,如果你资源已经不存在了或者明确禁止缓存,那浏览器也不可能使用缓存,这也是解决缓存问题的办法
强制缓存
强制缓存两个请求头,
expires
和
cache-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-modified
和
etag
两个请求头,这里我就不多讲了
但是要注意,强制缓存要优先于协商缓存,所以嘛,就算你更新了,浏览器依旧会读取缓存,这也就是问题的由来,解决办法很简单,要么直接禁用缓存,告诉浏览器不准使用我的缓存,每次都从服务器加载。要么就是把文件名字改了,缓存名字对不上也就不会读取缓存了
解决办法
知乎上有个回答说的挺好
浏览器是好人(meta),浏览器有点坏(版本号),浏览器老子看你不爽了,我要“欺骗你”(md5)
meta缓存头设置为禁止缓存
在html的head标签中加入下面内容,就可以禁止浏览器读取缓存
<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
即可,比如
custom.css?v=1.0
main.js?v=2.0
当然版本号也可以自动添加随机数,不过这样就违背了版本号的初衷了,这样同样浏览器在资源没修改的时候也不能加载缓存,影响体验 随机版本号的添加方法,使用一个随机函数即可,当然,这样就只能通过js中写js的调用语句,比如
document.write( " <script src='test.js?v= " + Math.random() + " '></s " + " cript> " )
或者是
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文件,添加版本号是再自然而然不过的一件事了
参考链接
- 彻底理解浏览器的缓存机制
- 缓存(二)——浏览器缓存机制:强缓存、协商缓存