Yuguo.us

前端工业化2:缓存

Introduction

user

余果

全栈工程师,《Web全栈工程师的自我修养》作者。


Featured

front-end

前端工业化2:缓存

Posted by 余果 on .

There are only two hard things in Computer Science: cache invalidation and naming things.

– Phil Karlton

缓存基础

在开始讲缓存技术之前,需要先了解设置缓存有两个作用:

  1. 对客户来说,减少请求,可以更快加载页面。如果客户是在手机上用3G访问页面,那也能节省他的流量。
  2. 对网站来说,减少带宽压力,如果有1亿的访问量,如果能在CSS上节省10k,那也是非常庞大的流量节省。

从技术上讲,有两种技术被统称为“缓存”。

一个被称为高速缓存,浏览器直接从缓存中读取文件而不发出任何请求。另一个是HTTP 304(Cache Control),浏览器会询问服务器文件是否更改,服务器回答没有修改(304),或者修改了(200)。

想要详细的了解,可以看看我去年的一篇旧文如何正确设置缓存

结论是:

200(缓存)是最快的,因为没有请求发生。304则产生了HTTP请求:浏览器发送一个带有If-Modified-Since的请求,服务器根据情况返回304来告诉浏览器使用本地文件。

所以304比200(缓存)慢一点,静态文件都应该使用Expires头来减少请求,提高访问速度。(根据HTTPWATCH的说法:“Don’t cache HTML, Cache everything else forever”)

Ajax与缓存

Ajax调用就像任何其他的HTTP请求一样可以用来构建一个网页。然而,由于其动态的性质人们常常忽略了可以缓存它们而从中受益。

高性能网站建设的第14条规则:

缓存Ajax

确保您的Ajax请求遵循这条规则,特别是包含一个Expires头。

现代浏览器的HTTP系统和缓存系统要比Ajax的XMLHttpRequest对象更靠近底层. 在这个层面上,浏览器并不知道或关心Ajax请求。它只是服从正常的基于从服务器返回的HTTP响应头缓存规则。

如果你已经知道HTTP缓存,您可以将这种知识应用到Ajax的缓存。

当然,如果您使用Ajax的POST方法,这并不适用,因为POST请求不会被缓存。如果您的Ajax请求有安全性要求,你应该总是使用POST方法,例如:银行帐户的资金转账。

缓存与更新缓存

在几年前,我们团队控制缓存的唯一办法就是把资源丢到/ac/路径上去发布,CDN对这个文件夹的处理方式是输出的HTTP header设置更长的缓存时间。而要更新缓存就是手动修改对文件引用路径的query string。

历史在进步,后来我们的CDN权限支持url query string的方法来吐出对应的缓存header。从这个时候开始,我们的资源请求都变成了这个样子:

http://ctc.qzonestyle.gtimg.cn/qzone_v6/icenter.css?max_age=19830212&d=131016151112

通过修改query string,就可以控制返回header的cache-control。后面的d则是无意义的字符串,当有新版本的时候我们需要半自动去修改它,对于浏览器来说只要修改了query string,它就认为是请求了新文件,从而放弃本地缓存而重新请求。

这种通过修改query string更新缓存的方法有几个问题:

  1. 这种方法是替换的方法来发布,那么在“html生效”和“css生效”之间如果出现任何时间差,哪怕是10s,就会出现错误的情况。尤其是雪碧图如果是自动计算生成的,错位就很严重了,几乎满屏的雪碧图都会错位。腾讯有几十台CDN,无法保证生效时间的精确性。
  2. 可能遭到缓存攻击,具体可以看看前端工程与性能优化(上):静态资源版本更新与缓存
  3. 可能被网络提供商保存一份旧文件的副本,这样即使我们更新了&d=xxxx这个时间戳,网络提供商也仍然给你老的文件。也就是说浏览器认为这是新文件,向网络重新请求,而网络提供商可能认为这还是老文件,所以给你旧文件。
  4. 发布流程麻烦,前端工程师需要同时关注样式的生效,和时间戳的生效。
  5. 缺乏对组件的动态管理和统计,因为我们相当于在本地生成了一个完整的public静态资源文件夹,然后发布出去,从那以后就跟前端没有关系了。

修改文件名

现在我们前端同学经过跟运维同事的讨论,总结出一套更好的更新缓存的办法,修改资源的名称。所以如果现在如果你可以访问QQ空间公测版(V8)的话,抓包会发现这样的CSS请求:

http://ctc.qzonestyle.gtimg.cn/aoi/icenter-wei131025143515.css

新的文件名有很多好处:

  1. 这种方法采用增量的方法来发布,不存在“html生效”和“css生效”之间的延迟,因为css可以提前发布生效,html再调用新的文件
  2. 遇到问题回滚简单,不用回滚所有的静态资源,只需要回滚html
  3. 完全杜绝了网络提供商提供旧文件副本的问题
  4. 使用不规律的文件名,不可能遭到缓存攻击

我只是简单提到了运行原则,但是实际操作中有很多细节要处理,包括前端同学要注意的和运维同学在CDN上的工作量。新的缓存策略现在还在试行之中,所以也没有全面部署,只有在未来有了更自动化的方案的时候才会全面部署。

user

余果

https://yuguo.us

全栈工程师,《Web全栈工程师的自我修养》作者。