我们都知道对页面进行缓存能够有利于减少请求发送,从而达到对页面的优化。不过在我前端工作的生涯中一直以为前端就是写写页面,写写交互,就已经很了不起,这种没有志向的想法发导致我日后的工作一直处于瓶颈。做人嘛总要有梦想嘛,不然跟一条咸鱼有什么区别。最近我一直在关于前端优化的问题,原来对页面进行有效缓存对于响应速度会大大提高。我也是综合自己看到的几篇文章,谈谈看法,权当是一次学习笔记吧,有什么不对的请多多包涵。废话不多说,开始正题。
缓存机制
缓存分为服务端侧(server side,比如 Nginx、Apache)和客户端侧(client side,比如 web browser)。
服务端缓存又分为 代理服务器缓存 和 反向代理服务器缓存(也叫网关缓存,比如 Nginx反向代理、Squid等),其实广泛使用的 CDN 也是一种服务端缓存,目的都是让用户的请求走”捷径“,并且都是缓存图片、文件等静态资源。
浏览器缓存控制机制有两种:HTML Meta标签 vs. HTTP头信息<META HTTP-EQUIV="Pragma" CONTENT="no-cache">上述代码的作用是告诉浏览器当前页面不被缓存,每次访问都需要去服务器拉取。使用上很简单,但只有部分浏览器可以支持,而且所有缓存代理服务器都不支持,因为代理不解析HTML内容本身。1、服务端缓存相关
什么是Etag?什么是Last-Modified?等等这些,都是什么鬼,以前我一看到都是直接懵逼。
首先我们要先根据http请求头以及响应头 先看一些跟缓存相关的报文头cache-control, if-none-match, if-modified-since, Etag,expires, last-modified,
request header缓存相关:cache-control:其缓存指令对于前段常用的有如下no-cache、no-store、max-age这几个值;分别来说一下no-cache:表面意为“数据内容不被缓存”,而实际数据是被缓存到本地的,只是每次请求时候直接绕过缓存这一环节直接向服务器请求最新资源,由于浏览器解释不一样,例如ie中我们设置了no-cache之后,请求虽然不会直接使用缓存,但是还会用缓存数据与服务器数据进行一致性检测(也就是说还是有几率会用到缓存的),firefox中则完全无视no-cache存在,详细解释见no-store;no-store:指示缓存不存储此次请求的响应部分。与no-cache比较来说,一个是不用缓存,一个是不存储缓存;按理来说这个设置更加粗暴直接禁用缓存,但是具体实现起来 浏览器之间差异却特别大,一般不会直接用该字段进行设置,不过no-store是为了防止缓存被恶意修改存储路径导致信息被泄露而设置的,毕竟有它的用处,在firefox中实现缓存是通过文件另存为将缓存副本保存到本地,直接利用no-cache对其是无效的,如果加上no-store设置的话 则可以起到与no-cache一样的效果;即:cache-control:no-cache,no-store;可以确保在支持http1.1版本中各大浏览器回车后退刷新无缓存;再加上Pragma: no-cache设置兼容版本1.0即可(不过为了防止一致性检测时候的万一我们还是最好加上一致性检测的内容,如下所示几种方式);max-age:例如Cache-control: max-age=3;表示此次请求成功后3秒之内发送同样请求不会去服务器重新请求,而是使用本地缓存;同样我们如果设置max-age=0表示立即抛弃缓存直接发送请求到服务器一致性检测分为两种方式:1.检测日期是否过期,检测资源是否更新;if-none-match:该字段与响应中的eTag一起使用,表示检查实体是否有更新改变;客户端第一次发送请求时候响应报文会包含字段Etag,表示资源状态,当资源改变后该值也会改变(客户端不必关心该值怎么生成)然后缓存保存下该字段,第二次已经有该缓存时候在浏览本地缓存时候会将该值赋给if-none-match字段发送给服务器,服务器将发送的值与当前的状态进行对比,如果值一样的话则答复304去使用缓存数据,如果值改变了则发送最新数据给客户端替代现有缓存数据,并且返回状态200;if-modified-since:该字段与last-modified配合使用,跟上述原理差不多,都是响应端先返回一个last-modified时间字段,再次请求时候 request头部会将缓存中的last-modified字段拿出来赋给if-modified-since,发送给服务器,服务器去判断时间是否过期,如未过期则返回304,告诉客户使用缓存数据,如果过期则重新返回一个last-modified并且返回200;repsonse header缓存相关:Etag:刚才也说过 是跟if-none-match配合去使用,它根据实体内容生成的一段hash字符串(类似于MD5或者SHA1之后的结果),可以标识资源的状态。 当资源发送改变时,ETag也随之发生变化。使用Etag主要是为了解决根据时间无法解决的问题:比如文件修改频繁(秒之内修改),导致根据时间无法判断是否更新;以及修改时间变了,但是内容没变(我们应该认为该文件是没变的)expires:表示缓存过期时间例如:expires:Mon Dec 30 2011 11:01:19 GMT,跟cache-control中的max-age作用一样,不过在碰见max-age之后,该值会被覆盖从而被max-age替代;last-modified:表示文件最后修改时间;另外响应端的报文头也有对cache-content的规定,与request大体相同,另有未提及的 欢迎大家补充使用缓存:
默认情况下,浏览器都会使用缓存数据,
在f5刷新情况下 浏览器会发送一致性验证去服务器验证是否使用缓存,而浏览器直接回车则表示直接应用缓存不需要去服务器验证;所以我们就按照f5刷新去解释实现使用缓存:
一般来说前端默认是使用缓存的,默认情况下服务器端以及前端都会使用缓存数据,或者是根据etag或者是根据max-age或者是根据expires根据服务器不同去不同实现;
实际中大部分不需要我们手动去实现,而有些我们不确定是否使用缓存的情况下我们可以手动加以干涉强制使用缓存数据:
例如某个静态文件包括html或者图片我们需要使用缓存来提高处理速度,
方法一:
在服务器进行配置其max-age或者expires使其设置一个过期值为当前一年之后。这样每次进行检验时候都会使用缓存中文件.例如在.htaccess中
<IfModule mod_headers.c>
<FilesMatch ".(gif|jpg|jpeg|png|ico)$">
Header set Cache-Control "max-age=604800"
</FilesMatch>
方法二:
前端设置if-modified-since去设置一个上次修改时间大于当前日期,
方法三:
服务器端根据etag去判断是否匹配来根据实际业务来使用缓存;
后面两个方法属于弱缓存数据头,需要浪费http连接,所以建议使用第一种方式;
禁用缓存:
方法一:
可以在meta标签标明<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
方法二:
也可以动态去setRequestHeader,强制不用缓存设置组合如下:
cache-control='no-cache,no-store'
pragma='no-cache'
if-modified-since=0;
方法三:
请求端设置if-modified-since为已经过期的某个时间,可以是几年前或者几十年前。
方法四:
服务端设置Expires为过期某个时间,例如php中header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
实际开发中如果需要一致性检测则尽量去配合Etag以及last-Modified去进行比较然后返回使用缓存还是新数据;这个有点偏服务器端了,不再赘述
方法五:
url后面加随机数或者时间戳url += “&random=” + Math.random()这个方法js以及php经常用,原理就是每个请求的url都不一样这样一来缓存中找不到对应数据,就自动去服务器寻找最新资源;
2、浏览器缓存相关
浏览器缓存是浏览器端保存数据用于快速读取或避免重复资源请求的优化机制,有效的缓存使用可以避免重复的网络请求和浏览器快速地读取本地数据,整体上加速网页展示给用户。浏览器端缓存的机制种类较多,打开浏览器的调试模式->resources左侧就有浏览器的8种缓存机制。
上述的缓存机制js都有相关的api进行操作,请自行查询。上面其实都是我粘贴复制的,因为这几篇文章让当时的我有种醍醐灌顶的感觉。详情可以参考如下链接
1、
2、
3、