为你的网站添加Cache-Control

2020-03-09

引言

在社区论坛和技术网站中,我们经常会听到和CDN,缓存(Cache)相关的讨论,不仅仅是在网站服务器中,而且在计算机底层硬件,例如在CPU,内存,磁盘,显卡中,也有缓存,而且缓存的速度和容量大小经常被作为关键性能指标之一,今天我们来谈一谈缓存(Cache)在网页服务器(Web Server)中的使用,我们还会顺便谈到CDN(Content Delivery Network),以及CDN和缓存是如何加快网页的加载速度的.

缓存的概念

首先,什么是缓存(Cache)?首先你可以暂且认为这个翻译是恰当的.缓,就是暂缓的意思,也有暂时的意思,还有缓解的意思,稍后我们会知道缓存真的有暂时,也有缓解的意义.存,就是存储了,在计算机中存储数据和文件的存储.而且,Cache还被翻译为『快取』,意思是有了缓存的帮助,资源的读取速度变快了.

一个例子:书架和书桌

书架和书桌都能够存储书籍,但是由于种种原因,书桌上能够放置的书的数量往往比书架上能放置的书要少,并且人们会更倾向于把经常阅读的书放在书桌上,不那么经常阅读的书方在书架上,而不是将经常阅读的书放在书架上,不常阅读的书堆满书桌.显然,长期来看前者比后者的习惯更节省时间.书桌,起到了缓存的作用,或者说,书桌为书桌的使用者缓存着最常阅读的书.

一个例子:作为『商品』的缓存

可乐作为从工厂中批量生产出来的商品,必须经由运输工具运输到零售商店,才能被人们购买,因为如果可乐不被(通过各种渠道)运输到零售商店,那人们就只能跋山涉水,走很远的路,才能到工厂中获取到可乐,这个路上的时间是非常久的.

全国性的大型电子商务企业,会在各个地方都布置仓库用于存放商品,通过合理地估计各个地方对各种商品的需求,在商品需求发生之前,提前将商品运送到离商品需求地最近的仓库,这样可以快速地将商品送达客户的手中.早期的网购订单比较快的通常也需要三到四天才能送到客户的手中,现在在很多地方,订单已经能在当天之内送达,而这些年来用来运送货物的普通交通工具并没有太大的提速.

所以,什么是缓存?

我不建议大家急着尝试去给自己刚开始认识的概念下定义或者是直接开始从定义上去理解它,但是这个新概念的性质是必须要知道的.在以上两个例子中,被称之为缓存的东西都是通过提前将被频繁访问的资源放在离需求者更近的地方,来减少需求者需要访问资源时接近资源所需的时间,从而加快了资源访问的速度.

所以缓存有两个性质,其一是缓存能够加快访问资源的速度,其二缓存需要在访问事件发生之前提前在时间和空间上对资源重新布局,否则起不到加速的效果.一句话,我们知道缓存是加速资源的访问的,并且缓存要提前布局资源,就够了.目前为止,把缓存看做是备忘录,是没有问题的.

计算机网络中的缓存

电子信号和电子信号的不同组合所表达的信息通过导体和电磁场在机器之间进行传输,科学家和工程师们发明并构建了现代的庞大的计算机网络,基于这个全球通联的计算机网络,有一类流行的应用受到了特别多的关注和讨论,这类应用被叫做万维网(World Wide Web).

万维网的具体的表现形式就是,人们通过计算机可以打开「网页」(Web Page),网页在用户看来是计算机屏幕上显示的文字、图像和音乐的组合,是一类被称作『浏览器』(Web Browser)的计算机软体将网页显示起来,另外一类被称作『网页服务器』(Web Server)的计算机软体负责『制作』或者『提供』(Serve)网页,网页则通过线缆和空间中的电磁场从服务器的手中被『运送』到浏览器的口中,再由浏览器将网页以以一种用户能接受的形式展示出来给用户.一个网页服务器有时候不只会提供一张网页,如果一个网页服务器提供着多张网页,我们说这个服务器维持着一个网站,用户访问的也可以叫做网站,网页和网站的关系:网页是一张纸,而网站就是一本书.

页面缓存

在最简单的形式中,一个网站只架设在一台服务器上,当用户在浏览器输入这个网站的网址,浏览器就会向这个服务器发起一个请求,当然,每次可以是请求不同的内容,然后服务器把相应的请求所请求的内容准备好,返回给浏览器,一次请求就这么完成了.

但是浏览器发出的请求到达服务器需要时间,而服务器生成内容之后(我们暂且假设服务器生成内容很快),生成的内容从服务器发送,到浏览器收到,也是需要时间,所以,按照这种模型,打开一个网页需要的时间等于

$$ \Delta t = \Delta t_0 + \Delta t_1 $$

其中,$\Delta t$是用户在浏览器打开一个网页需要的时间,$\Delta t_0$是请求从浏览器发送到服务器的时间,而$\Delta t_1$则是请求的内容从服务器发回浏览器需要的时间.

现在假设$\Delta t_0$或者$\Delta t_1$非常久,即请求发送到服务器,或者请求内容由服务器返回非常耗时,有什么办法,$\Delta t$没这么慢呢?或者说有什么办法缓解这种高延迟的网络环境带来的页面加载慢的问题呢?

如果说服务器的内容是固定的,不变更的,如果说浏览器也知道这一点,那么只需在第一次请求的内容收到后,把内容存起来,存在本地,那么下次再有同样的请求,浏览器直接把存储好的页面取出,就不用再等待$\Delta t_0 + \Delta t_1$的时间了.这其实就是页面缓存最初的想法.

然而很难认为现实中服务器提供的内容不随着时间变更,比如说博客,新闻网站,门户网站都是经常更新的.这时候,把获取到的页面存起来的这种做法,是不是就没有意义了呢?毕竟用户并不希望一直看到的都是旧的过时的内容,用户事实上希望看到服务器现在所提供的内容.

在这种情况下,把内容提前存起来的这种做法,我们就叫它缓存吧,这时候,缓存仍然是可行的,因为不管是博客,还是新闻网站,还是门户网站,甚至是商品展示网站,它的页面是不可能做到时刻更新的,更具体地说,每一次更新和上一次更新,总会有这么一个间隔.干脆服务器就告诉浏览器,更新的最短周期是多少,那么浏览器,不就可以继续使用缓存的方法,来避免重复的请求了么?而且缓存实际上对服务器也是有利的,因为有了缓存浏览器不必向服务器发起不必要的请求,服务器的计算资源的消耗减少了,同样的计算资源下,能为更多的浏览器服务.

刚才我们说的这个网站的『最短更新周期』,服务器其实是可以主动告诉浏览器的,原因之一是浏览器做了缓存能减轻服务器的压力,原因之二是服务器知道文章的最短更新周期,由站长或者系统管理员设置一下就好了.这样,服务器每次发送响应内容时,附加一个该响应内容的『最后修改时间』,外加一个该内容的『最短更新周期』,浏览器照样缓存收到的内容,并且由于知道缓存多久会『过期』,只要在缓存过期之后立刻删除缓存并且在下一次开始请求时再重建缓存就好了.这样一来,用户能看到服务器的最新内容,浏览器也能避免不必要的重复请求.

====还没写完待会儿接着写…====

参考文献

[1] HTTP caching - HTTP | MDN

[2] Cache-Control - HTTP | MDN

[3] RFC 7234 - Hypertext Transfer Protocol (HTTP/1.1): Caching

[4] RFC 5861 - HTTP Cache-Control Extensions for Stale Content

概念理解httpcache

RFC 7234:阅读与思考

记我的第一次GitHub Pull Request(完结篇)Fork与PR