浏览器缓存原理是前端面试中必问的一道经典题目,也是前端开发必须掌握的知识。本文介绍浏览器缓存在实际项目上的应用,希望有缘看到这篇文章的小伙伴,不止是准备面试,而是真的掌握这一知识点。如果你比较懒,看懂文章的简单概括揣摩一下就可以当面试题的答案。如果你想要多了解一下,不妨看完文章。
强缓存跟协商缓存说的是浏览器请求静态文件(js、html、css、图片以及其它文件)缓存的使用策略,作用是提高页面加载速度。
浏览器使用缓存的过程是:先执行强缓存,查看本地有没有这么一个文件,文件的状态(expires和cache-control)是不是过期了,没有过期就直接用本地缓存不向浏览器发送请求,如果过期了就执行协商缓存,到服务器询问一下能不能继续用缓存(last-modified和etag),能就继续用本地的缓存,不能就加载新的文件。
缓存设置优先级是:
Cache-Control > expires > Last-Modified|etag
强缓存的状态码是 200(from memory cache)
协商缓存的状态码是304
从前面的简单概括来看,一旦设置了过期时间,浏览器就不会在没过期的时候向服务器发送请求,这就会导致你服务器实际上更新了文件,但是浏览器不知道,所以强缓存一定要慎重使用。
html是必须加上不使用强缓存配置的,不然你可能需要客户清理浏览器缓存才能看到你的代码更新
下面是html配置,
<head>
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" CONTENT="no-cache">
<meta http-equiv="expires" content="-1">
head>
但是上面的meta加上了之后可能也没用,这个时候你要看看服务器端的配置了,这里只说nginx
location ~ .*\.(htm|html )$ {
add_header Pragma "no-cache";
# 60秒内不会访问服务器
# add_header Cache-Control "max-age=60";
# 不缓存
add_header Cache-Control "no-cache";
add_header expires -1;
}
#过期时间为30天示例
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
expires 30d;
}
# 时间设置永不过期示例
location ~ .*\.(js|css)$ {
expires max;
}
其实js、css跟图片这些资源,webpack打包的时候会给文件名加随机数(hash),每次更新页面,其实访问的是新的静态文件,所以我们在使用的时候采用的策略是永不过期。可以看看dist文件夹
强缓存基本上运维加webpack都给做好了,所以对缓存不是很懂的小伙伴不太感受得到自己实际上已经在使用他们。
但是一旦你的服务器跟html上面都没配置,那浏览器会自己判断使用自带的配置,什么都不配置的结果就是缓存时间不可控,性能差。
协商缓存更多用于静态文件服务器(如cdn),属于主动优化的一部分,需要先配置不使用强缓存,或者强缓存有时限。
举个例子,我们每次打包项目,图片都加上了hash随机数,导致了每次更新版本,图片都得重新加载,但是其实很多时候我们的图片并不会轻易变化。这个时候图片存到单独的静态文件服务器或者是cdn上会更好一些,但是我们也要保证图片真的需要更新的时候能被更新到,所以这个时候协商缓存就派上用场了。(c端项目更推荐cdn,有兴趣可以搜搜cdn相关的文章,作者以后也会写)
协商缓存主要是服务器端的配置,这里介绍nginx
# 开启Last-Modified方式二
location ~* \.(gif|jpg|jpeg|png|bmp|swf)$ {
# 开启关闭etag,有些版本默认开启有些默认关闭,按需配置
etag off|on;
# 开启Last-Modified方式一,默认是开启的 on
if_modified_since off|on;
# 自定义Last-Modified的时间可以手动触发刷新,要配合if_modified_since off, 慎用
add_header Last-Modified 'Fri, 12 May 2006 18:53:33 GMT';
# 不想要就置空
# add_header Last-Modified "";
add_header Cache-Control "public";
# 设置不用用强缓存
expires -1;
}
实际上协商缓存nginx1.7.3及以上的版本也默认开了,所以,你只要确保需要使用协商缓存的文件没有被强缓存就行了。
Last-Modified不需要自己设置时间,nginx会去查文件修改日期。
etag是更新静态文件会打一个标记(tag),是一串nginx自带算法生成的字符串,长这样
etag:“50b1c1d4f775c61:df3”
Etag 是http版本迭代对 Last-Modified的优化补充,主要为了解决:
如果Last-Modified没起作用,试试把Etag 打开
因为强缓存的优先级高于协商缓存,所以有下面的属性优先级关系
Cache-Control > expires > Last-Modified|etag
服务器收到请求则会先判断资源的 last-modified,再判断 etag ,必须都没有过期,才能返回 304,所以它们是同时生效的
nginx一般都是运维配置好了,而html上的meta是需要前端同学手动添加的。所以一旦缓存出了问题,你就去看html设置了缓存没,再问一问运维同事看看nginx的相关配置是怎样的。
html中的meta跟服务器的header属性取值是一样的,这里补充一下避免使用的时候还得翻文档