前端性能优化之HTTP缓存策略

栏目: 后端 · 前端 · 发布时间: 6年前

内容简介:很多时候,当打开浏览器的开发者工具,查看网络请求,对于资源大小(Size)选项,除了有具体的数字大小,还有from memory cache、from disk cache字段之类出现。这里就有很多疑问,这些字段代表着什么意思?这些字段又是谁来决定的?从字面意思理解,大概也能猜到,这些字段代表着缓存位置。 按优先级,Size选项字段可分为:

很多时候,当打开浏览器的开发者工具,查看网络请求,对于资源大小(Size)选项,除了有具体的数字大小,还有from memory cache、from disk cache字段之类出现。

这里就有很多疑问,这些字段代表着什么意思?这些字段又是谁来决定的?

前端性能优化之HTTP缓存策略

缓存位置

从字面意思理解,大概也能猜到,这些字段代表着缓存位置。 按优先级,Size选项字段可分为:

  • from Service Worker
  • from memory cache
  • from disk cache
  • 真正的网络请求(显示资源的具体大小)

Service Worker

本质是作为服务器与客户端之间的代理服务器,伴随着PWA出现。Service Worker真正意义上将缓存控制权交给了前端,相比于LocalStorage、SessionStorage,后两者只是单纯的接口数据缓存,例如用户信息(一个对象)、列表信息(一个数组),而前者可以缓存静态资源,甚至拦截网络请求,根据网络状况作出不同的缓存策略。当然,这不是本文讨论的重点。

memory cache

顾名思义,这个是将资源缓存在了内存中。事实上,所有的网络请求都会被浏览器缓存到内存中,当然,内存容量有限,缓存不能无限存放在内存中,因此,注定是个短期缓存。

内存缓存的控制权在浏览器,前后端都不能干涉。

disk cache

与内存缓存相对的,这个是将资源缓存在硬盘中。虽然相比于内存,硬盘的读取速度要慢很多,但总比没有强。

硬盘缓存的控制权在后端,通过什么控制呢?通过HTTP响应头控制,这是本文重点讨论的。

缓存策略

disk cache也叫http cahce,因为其严格遵守http响应头字段来判断哪些资源是否要被缓存,哪些资源是否已经过期。绝大多数缓存都是disk cache。

disk cahce分为强制缓存与对比缓存。

强制缓存

控制强制缓存的有两种http响应头字段:

Expires: Fri, 08 Feb 2019 05:37:33 GMT

字段的值就代表了资源的过期时间,不过这个值是相对于客户端,并且客户端本地时间可以任意修改,因此这个字段并不可靠。Expires字段是Http 1.0的,Http 1.1 用Cache-Control字段替代它:

Cache-Control: max-age=2592000

Cache-control字段使用了绝对时间,单位为秒,即最大有效时间,在有效时间内,客户端直接从硬盘中读取资源。

看个例子,用Node.js搭建一个静态资源服务器,设置Cache-Control: max-age=2592000,每次请求都会被服务器打印出:

const server = http.createServer((req, res) => {
    console.log(`收到请求,请求地址为: ${req.url}`);
    fs.readFile(path.resolve(__dirname, './image.png'), (err, file) => {
        if (err) {
            res.end(err.message);
        }

        res.setHeader('Cache-control', 'max-age=2592000');
        res.end(file);
    });
}).listen(3000);

console.log('localhost:3000服务已开启!');
复制代码
前端性能优化之HTTP缓存策略

第一次访问:

前端性能优化之HTTP缓存策略
前端性能优化之HTTP缓存策略

第二次访问:

前端性能优化之HTTP缓存策略
前端性能优化之HTTP缓存策略

可以看到,第一次请求,浏览器根据响应头中的Cache-Control字段,将资源缓存在硬盘中,第二次请求,浏览器直接从硬盘中读取资源,并没有发送网络请求到服务器。

Cache-Control字段有以下可取值:

  • max-age=xxx,最大的有效时间
  • must-revalidate,如果超过了max-age的时间,必须向服务器发送请求,验证资源的有效性
  • no-cache,基本等价于max-age=0,由对比缓存来决定是否缓存资源
  • no-store,真正意义上的不缓存
  • public,所有内容都可以被缓存
  • private,所有内容只有客户端可以缓存,代理服务器不能缓存。默认值

对比缓存

不同于强制缓存,浏览器直接根据响应头Cache-Control字段直接判断缓存资源是否有效,对比缓存需要再次向服务器确认。

Last-Modified & If-Modified-Since

服务器通过响应头Last-Modified告知浏览器,资源最后被修改的时间:

Last-Modified: Fri, 08 Feb 2019 15:20:04 GMT

当再次请求该资源时,浏览器需要再次向服务器确认,资源是否过期,其中的凭证就是请求头If-Modified-Since字段,值为上次请求中响应头Last-Modified字段的值:

If-Modified-Since: Fri, 08 Feb 2019 15:20:04 GMT

服务器会接收If-Modified-Since字段的值与被请求资源的最后修改时间作比较

如果If-Modified-Since的值大于被请求资源的最后修改时间,则说明浏览器缓存的资源仍然有效,服务器会返回304状态码,告知浏览器直接取缓存即可。其中服务器返回的只有Http头部,并不包含主体(不然就没有缓存的意义了)。

否则,就跟正常的请求一样,服务器返回200状态码,并附带最新的资源。

看个例子,稍微修改下刚才的Node.js代码:

const server = http.createServer((req, res) => {
    console.log(`收到请求,请求地址为: ${req.url}`);

    const filename = path.resolve(__dirname, './image.png');

    fs.stat(filename, (err, stat) => {
        const lastModified = stat.mtime.toUTCString();

        if (lastModified === req.headers['if-modified-since']) {
            res.writeHead(304, 'Not Modified');
            res.end();
        }
        else {
            fs.readFile(filename, (err, file) => {
                if (err) {
                    res.end(err.message);
                }
                
                res.setHeader('Last-Modified', lastModified);
                res.end(file);
            });
        }
    });
}).listen(3000);

console.log('localhost:3000服务已开启!');
复制代码

第一次请求:

前端性能优化之HTTP缓存策略

第二次请求:

前端性能优化之HTTP缓存策略

比对两次请求可以看到,除了状态码变成了304,资源大小也从57.8K降到了90B,这也证明响应中不包含http主体。

Etag & If-None-Match

Last-Modiflied与Expires一样,也是有缺陷的。如果,资源的变化的时间间隔小于秒级,比如说是毫秒级的,或者说资源直接是动态生成的,那根据Last-Modified判断,资源就是每时每刻都最新的,即被修改过!

所以,Etag & If-Node-Match 就是来解决这个问题的。

Etag字段的值为文件的特殊标识,一般都是hash生成的,服务器存储着资源的Etag值。接下来的流程都与Lst-Modified & If-Modified-Since一致,只不过,比较的值从最后修改时间变成了Etag值。

Etag的优点在于,对于动态资源或者现在流行的Restful API返回的JSON数据,这些是没有修改时间这一说法的,但是Http标准并没有规定Etag值如何生成,因此我们通过代码自己生成Etag值。当然,计算Etag值会消耗服务器性能。

优先级

强制缓存与对比缓存是可以同时存在的,并且强制缓存的优先级高于对比缓存。实际应用中,也是两者共同使用的。

看个例子,在响应头中同时加上Cache-Control与Last-Modified:

res.setHeader('Cache-control', 'max-age=600');
res.setHeader('Last-Modified', lastModified);
复制代码

第一次请求:

前端性能优化之HTTP缓存策略

第二次请求:

前端性能优化之HTTP缓存策略

可以看到,虽然有Last-Modified字段,但还是直接从硬盘中获取资源。


以上所述就是小编给大家介绍的《前端性能优化之HTTP缓存策略》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

How to Think About Algorithms

How to Think About Algorithms

Jeff Edmonds / Cambridge University Press / 2008-05-19 / USD 38.99

HOW TO THINK ABOUT ALGORITHMS There are many algorithm texts that provide lots of well-polished code and proofs of correctness. Instead, this one presents insights, notations, and analogies t......一起来看看 《How to Think About Algorithms》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具