HTTP缓存

HTTP缓存

十一月 04, 2020

前端开发好的页面是直接面向用户的,如果打开页面的加载时间过久,会直接影响体验或者被用户直接关掉。所以前端的性能事关重要,那我们如何优化来提高页面加载性能呢?首先要了解从用户输入一个网址到页面呈现出来整个过程,依次对这些过程进行优化。

输入URL到页面渲染过程

  1. DNS解析

    当用户通过域名访问的时候,首先浏览器会去找域名对应的ip地址,整个过程如下:

    1. 首先会去浏览器缓存找是否访问过此域名,有则使用,没有进入下一步;
    2. 本地HOST文件寻找,没有进入下一步;
    3. 本地服务提供商(简称ISP)查找,没有进入下一步;
    4. 首先向根域名服务器发送DNS查询请求,返回可能保存了该域名的一级域名服务器地址;本地主机再根据返回的地址,向一级域名服务器发送查询请求,一直迭代直到找到对应的域名存放的服务器,向其发送DNS查询请求,返回域名对应的ip。
  2. TCP/IP连接

    三次握手

  3. 浏览器发起请求下载所需资源

  4. 浏览器渲染

    拿到从服务器下载的静态资源后,浏览器会开始解析html,css及js进行渲染:

    1. 解析HTML构建DOM树
    2. 解析CSS构建CSS DOM
    3. 两者合并生成Render tree
    4. layout render tree
    5. 根据render tree进行渲染
  5. 断开连接

    四次挥手

HTTP缓存

3884731615-5b5eb9db0731a_articlex

  1. 强缓存

    浏览器直接从本地获取的缓存,不需要服务器参与,主要是根据时间来判断缓存是否有效:

    • Expires

      HTTP/1.0的产物,保存一个缓存失效的绝对时间,超过这个时间则缓存失效

    • Cache-Control

      HTTP/1.1的产物,是一个相对时间,要加上开始时间进行判定,常用指令如下:

      • no-cache:不使用强缓存,需要使用协商缓存,这个字面意思容易混淆
      • no-store:禁用缓存
      • public:表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存,该响应对应的请求方法是POST
      • private:表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)

    浏览器会优先处理Cache-Control,经过两个判断后,如果命中缓存,则直接返回200,使用本地缓存;如果未命中,则进入协商缓存判断。

  2. 协商缓存

    强缓存有一个缺点,就是服务器端内容有更新的话,而客户端还是使用旧的缓存,所以需要服务器判断缓存是否可用,也就是协商缓存。

    • Last-ModifiedIf-Modified-Since

      文件最后修改时间,以秒计,判断过程如下:

      1. 浏览器从服务端下载资源时,服务器会在响应头上添加Last-Modified字段,表明该字段的最后修改时间;
      2. 浏览器再次向服务器请求资源时(未命中强缓存),会在请求头中添加If-Modified-Since字段,它的值是上次响应报文中的ETag的值;
      3. 服务器拿到请求头中的值,与资源的最新值做比较,如果相通,则命中缓存,直接返回304,表明浏览器可以继续使用本地缓存;如果不同,则返回200状态码和最新的资源。

      对于频繁变动的资源,由于该字段是以秒计时,如果1s内进行多次修改,服务器还是认为其命中了缓存,会存在误差;还有另外一种情况,比如我变动了文件,内容并没有变,但是服务器还是会生成新的最后修改时间,所以会有性能消耗。

    • ETagIf-None-Match(优先,精度比上面好)

      根据文件内容生成一个唯一标志字符,过程如下:

      1. 浏览器请求资源,服务器会在返回头中加ETag字段,资源内容变动时Etag随之改变;
      2. 浏览器再次请求时,会在请求头中加If-None-Match字段,也就是上次返回的Etag值;
      3. 浏览器取出请求头中的If-None-Match字段与文件最新的ETag做对比,如果相同则返回304,否则返回200和最新资源。