HTTP缓存作为性能优化的重要手段,当客户端向服务器请求资源时,会先抵达浏览器缓存,如果浏览器有“要请求资源”的副本,就可以直接从浏览器缓存中提取而不是从原始服务器中提取这个资源。
HTTP缓存都是从第二次请求开始的。第一次请求资源时,服务器返回资源,并在Response Header头中回传资源的缓存参数;第二次请求资源时,浏览器判断这些请求参数,命中强缓存就直接200,否则就把请求参数加到Request header头中传给服务器,看是否命中协商缓存,命中则返回304,否则服务器会返回新的资源。
===========================================================
HTTP缓存的优点:
- 减少了冗余的数据传输,节省了带宽;
- 减少了服务器的负担,大大提升了网站的性能;
- 加快了客户端加载网页的速度;
HTTP缓存的分类:
浏览器第一次向服务器发起HTTP请求后,服务器会返回请求的资源,并且在响应头中添加一些有关缓存的字段,例如Cache-Control、Expires、Last-Modified、ETag、Date等等,之后浏览器再向该服务器请求该资源就可以视情况使用强缓存和协商缓存。
1)强缓存:浏览器直接从本地缓存中获取数据,不与服务器进行交互;
2)协商缓存:浏览器发送请求到服务器,服务器判定是否可使用本地缓存;
两种缓存方式最终使用的都是本地缓存,前者无需与服务器交互,后者需要,判断使用HTTP缓存的流程如下:
强缓存:
如图01强缓存阶段所示的过程代表强缓存。用户发起了一个HTTP请求后,浏览器发现先本地已有所请求资源的缓存,便开始检查缓存是否过期。有两个HTTP头部字段控制缓存的有效期:Expires和Cache-Control,浏览器是根据以下两步来判定缓存是否过期的:
1)查看缓存是否有Cache-Control的max-age指令,若有则使用响应报文生成时间Date +max-age获得过期时间,再与当前时间进行对比;
2)如果没有Cache-Control的max-age指令,则比较Expires中的过期时间与当前时间,Expires是一个绝对时间。
注意:在HTTP/1.1中,当首部字段Cache-Control有max-age指令,会优先处理max-age。
经过上述两步判断后,若缓存未过期,返回状态码为200,则直接从本地读取缓存,这就完成了整个强缓存过程;如果缓存过期,则进入协商缓存或服务器返回新资源过程。
协商缓存:
当浏览器发现缓存过期后,缓存并不一定不能使用了,因为服务器端的资源可能仍然没有改变,所以需要与服务器协商,让服务器判断本地缓存是否还能使用。此时浏览器会判断缓存中是否有ETag或Last-Modified字段,如果没有,则发起一个HTTP请求,服务器根据请求返回资源;如果有这两个字段,则在请求头中添加If-None-Match字段、If-Modified-Since字段。如果同时发送If-None-Match 、If-Modified-Since字段,服务器只要比较If-None-Match和ETag的内容是否一致即可;如果内容一致,服务器认为缓存仍然可用,则返回状态码304,浏览器直接读取本地缓存,这就完成了协商缓存的过程,也就是图中的02协商缓存阶段;如果内容不一致,则视情况返回其他状态码,并返回所请求资源。如果没有If-None-Match,则再会比较Last-Modified与If-Modified-Since的内容是否一致,逻辑与If-None-Match基本一致,唯独响应头中不会再添加Last-Modified字段。
强制刷新:
前端资源更新到线上后用户浏览器不能自行更新,我们不能要求客户在系统更新后都进行一次缓存清理的操作。我们可以在资源请求的URL中增加一个参数,比如:js/main.js?ver=0.0.2,这个参数是一个版本号,每一次部署的时候变更一下,当这个参数变化的时候,强缓存都会失效并重新加载。这样一来,静态资源,部署以后就需要重新加载,即强制刷新。
===========================================================
总结:合理的使用HTTP缓存可以有效提升客户端的性能,但过分的设置缓存的有效期时长也可能会因资源未及时更新而导致客户体验问题,因此针对不同的访问资源以及场景还需合理评估以及分析。
注:文章均原创,部分图片及文字来源于网络,若涉及版权,请联系作者,将第一时间备注出处,谢谢。