通过互联网获取资源速度慢,成本高。为此,Http协议包含了缓存控制部分,使得Http客户端可以缓存并复用之前获取的资源,从而优化性能,提升体验。虽然Http中关于缓存控制的部分随着协议的演进有一些变化。但是我觉得,作为一个后端程序员,在开发web服务的时候,只关注请求头If-None-Match、响应头ETag、响应头Cache-Control就够了。因为这三个Httpheader可以满足你的需求,而且现在的浏览器大部分都支持这三个Httpheader。我们所要做的就是确保每个服务器响应都提供正确的HTTP标头指令,以指示浏览器何时以及可以缓存响应多长时间。缓存在哪里?上图中一共有三个角色,浏览器、web代理和服务器。如图所示,Http缓存存在于浏览器和Web代理中。当然服务器内部也有各种缓存,不过这已经不是本文要讨论的Http缓存了。所谓Httpcachecontrol,就是一种协议。通过设置不同的响应头Cache-Control来控制浏览器和Web代理对缓存的使用策略,通过设置请求头If-None-Match和响应头ETag来控制缓存的有效性验证。响应头ETag的全称是EntityTag,用来标识一个资源。在具体实现中,ETag可以是资源的哈希值,也可以是内部维护的版本号。但不管怎样,ETag应该能够反映资源内容的变化,这是Http缓存正常工作的基础。如上例所示,服务器返回响应时,通常会在Http头中包含一些关于响应的元数据信息,ETag就是其中之一。在此示例中,返回值为x1323ddx的ETag。当资源/文件的内容发生变化时,服务器应该返回一个不同的ETag。请求头If-None-Match对于同一个资源,比如上例中的/file,在发起请求后,浏览器已经有了/file的一个版本和这个版本的ETag,当下次用户If再次需要这个资源,当浏览器再次请求服务器时,可以使用请求头If-None-Match告诉服务器它已经有了一个ETag为x1323ddx的/文件。这样,如果服务器上的/file没有变化,也就是如果服务器上/file的ETag也是x1323ddx,服务器就不会返回/file的内容,而是返回一个304响应,告诉浏览器认为资源没有改变并且缓存有效。如上例所示,使用If-None-Match后,服务器只需要很小的响应就可以达到相同的结果,从而优化了性能。ResponseheaderCache-Control每个资源都可以通过HttpheaderCache-Control定义自己的缓存策略。Cache-Control控制谁可以在什么条件下缓存响应以及可以缓存多长时间。最快的请求是那些不必与服务器通信的请求:通过响应的本地副本,我们避免了所有网络延迟和数据传输的数据成本。为此,HTTP规范允许服务器返回一系列不同的Cache-Control指令,这些指令控制浏览器或其他中间缓存缓存响应的方式和时间。Cache-Control标头是在HTTP/1.1规范中定义的,它取代了以前用于定义响应缓存策略的标头(例如Expires)。目前所有的浏览器都支持Cache-Control,所以用它就够了。下面介绍一下在Cache-Control中可以设置的常用指令。max-age该指令指定从当前请求开始允许重用获得的响应的最长时间(以秒为单位)。例如:Cache-Control:max-age=60表示响应可以被缓存并再使用60秒。注意是的,在max-age指定的时间内,浏览器不会向服务器发送任何请求,包括验证缓存是否有效的请求,即如果服务器上的资源在这段时间内发生变化,则浏览器将不会收到通知,并将使用旧版本的资源。所以在设置缓存时间的长度时需要小心。如果public和private设置为public,则意味着响应可以缓存在浏览器或任何中继Web代理中。public为默认值,即Cache-Control:max-age=60等同于Cache-Control:public,max-age=60。当服务器设置为私有时如Cache-Control:private,max-age=60,这意味着只有用户的浏览器可以缓存私有响应,不允许任何中继网络代理缓存它——例如,用户的浏览器可以缓存包含用户隐私信息的HTML页面,但CDN不能。no-cache如果服务器在响应中设置了no-cache,即Cache-Control:no-cache,那么浏览器在使用缓存资源之前,必须先与服务器确认返回的响应是否发生了变化。如果资源未更改,则可以避免下载。这种验证之前的响应是否被修改是通过上面介绍的请求头If-None-match和响应头ETag来实现的。需要注意的是,no-cache这个名字有点误导。设置no-cache后,并不代表浏览器不再缓存数据,而是浏览器在使用缓存数据时需要确认数据是否仍然与服务器保持一致。如果设置了no-cache,ETag的实现不反映资源的变化,会导致浏览器的缓存数据保持不更新。no-store如果服务器在响应中设置了no-store,即Cache-Control:no-store,那么浏览器和任何中继的web代理都不会存储这次相应的数据。下次请求资源时,浏览器只能再次请求服务器,重新从服务器读取资源。如何确定资源的Cache-Control策略?下面的流程图可以帮助你。
