HTTP缓存
十一月 04, 2020
前端开发好的页面是直接面向用户的,如果打开页面的加载时间过久,会直接影响体验或者被用户直接关掉。所以前端的性能事关重要,那我们如何优化来提高页面加载性能呢?首先要了解从用户输入一个网址到页面呈现出来整个过程,依次对这些过程进行优化。
输入URL到页面渲染过程
DNS解析
当用户通过域名访问的时候,首先浏览器会去找域名对应的ip地址,整个过程如下:
- 首先会去浏览器缓存找是否访问过此域名,有则使用,没有进入下一步;
- 本地HOST文件寻找,没有进入下一步;
- 本地服务提供商(简称ISP)查找,没有进入下一步;
- 首先向根域名服务器发送DNS查询请求,返回可能保存了该域名的一级域名服务器地址;本地主机再根据返回的地址,向一级域名服务器发送查询请求,一直迭代直到找到对应的域名存放的服务器,向其发送DNS查询请求,返回域名对应的ip。
TCP/IP连接
三次握手
浏览器发起请求下载所需资源
浏览器渲染
拿到从服务器下载的静态资源后,浏览器会开始解析html,css及js进行渲染:
- 解析HTML构建DOM树
- 解析CSS构建CSS DOM
- 两者合并生成Render tree
- layout render tree
- 根据render tree进行渲染
断开连接
四次挥手
HTTP缓存
强缓存
浏览器直接从本地获取的缓存,不需要服务器参与,主要是根据时间来判断缓存是否有效:
Expires
HTTP/1.0的产物,保存一个缓存失效的绝对时间,超过这个时间则缓存失效
Cache-Control
HTTP/1.1的产物,是一个相对时间,要加上开始时间进行判定,常用指令如下:
- no-cache:不使用强缓存,需要使用协商缓存,这个字面意思容易混淆
- no-store:禁用缓存
- public:表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存,该响应对应的请求方法是POST
- private:表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)
浏览器会优先处理Cache-Control,经过两个判断后,如果命中缓存,则直接返回200,使用本地缓存;如果未命中,则进入协商缓存判断。
协商缓存
强缓存有一个缺点,就是服务器端内容有更新的话,而客户端还是使用旧的缓存,所以需要服务器判断缓存是否可用,也就是协商缓存。
Last-Modified和If-Modified-Since
文件最后修改时间,以秒计,判断过程如下:
- 浏览器从服务端下载资源时,服务器会在响应头上添加Last-Modified字段,表明该字段的最后修改时间;
- 浏览器再次向服务器请求资源时(未命中强缓存),会在请求头中添加If-Modified-Since字段,它的值是上次响应报文中的ETag的值;
- 服务器拿到请求头中的值,与资源的最新值做比较,如果相通,则命中缓存,直接返回304,表明浏览器可以继续使用本地缓存;如果不同,则返回200状态码和最新的资源。
对于频繁变动的资源,由于该字段是以秒计时,如果1s内进行多次修改,服务器还是认为其命中了缓存,会存在误差;还有另外一种情况,比如我变动了文件,内容并没有变,但是服务器还是会生成新的最后修改时间,所以会有性能消耗。
ETag和If-None-Match(优先,精度比上面好)
根据文件内容生成一个唯一标志字符,过程如下:
- 浏览器请求资源,服务器会在返回头中加ETag字段,资源内容变动时Etag随之改变;
- 浏览器再次请求时,会在请求头中加If-None-Match字段,也就是上次返回的Etag值;
- 浏览器取出请求头中的If-None-Match字段与文件最新的ETag做对比,如果相同则返回304,否则返回200和最新资源。