原文地址:

Caching Tutorial for Web Authors and Webmasters

1 什么是web缓存?人们为什么使用它们?

2 web缓存的类型

  2.1 浏览器缓存

  2.2 代理缓存

  2.3 网关缓存

4 web缓存如何工作

6 构建一个有缓存意识的站点用到的技巧

7 写有缓存意识的脚本

 

1 什么是web缓存?人们为什么使用它们?

web缓存位于一个或者多个服务器和一个或者多个客户端之间,监视其中的请求,节约响应的数量。例如:页面,图片和文件。如果对相同的url地址的另外一个请求,可以使用已有的响应,而不是向原始服务器重新请求。

使用web缓存有两个主要原因:

1、减小延迟。因为请求从缓存,这个离客户端更近的地方,得到响应,而不是从原始服务器。花费更少的时间获取内容并且呈现出来,使得web看起来响应更快。

2、减少网络传输。因为响应被重用,减少了客户端的带宽使用。如果带宽需要付费的话,还可以节省开支,保持对带宽的较小需求。

2 web缓存的类型

2.1 浏览器缓存

如果你打开现代浏览器的设置对话框,都会发现一个缓存项设置。允许你使用硬盘来存储缓存的内容。缓存都有相似的工作原理。它会检查内容是否新鲜,每次会话都会检查,也就是浏览器的一次调用。

这种缓存在你浏览已经浏览过的页面的时候非常有用,如果你查看同一张图片,浏览器会缓存起来,瞬间就可以显示出来。

2.2 代理缓存

代理缓存以相似的方式工作,但是规模更大。代理以相同的方式服务于成百上千的用户,大公司或者ISP通常在防火墙上面设置他们,或者是单独的设备。

因为代理缓存不是客户端或者原始服务器的一部分,他们位于网络的某个地方,请求会经过他们。使用他们的一个办法是设置你的浏览器代理,告诉浏览器使用那些代理。另外一个方法是拦截代理。拦截代理是通过网络底层是实现的,客户端不需要设置,甚至不需要知道他们的存在。

代理缓存是一种共享的缓存,同时不止有一个用户使用,同时有很多用户使用,使得他更擅长于减小延迟和减少带宽。因为常用的内容会被多次的使用。

2.3 网关缓存

和“反向代理缓存”一样,网关缓存也位于客户端和服务器的中间,他不是ISP部署用来减少带宽的,而是web站点管理员部署,使得站点更容易扩展,更可靠,拥有更好的性能。

有很多种方法可以将请求定位到网关缓存,典型的是用负载均衡,在客户端看来好像访问了原始服务器。

CDN(Content Delivery Network)也可以用来提供网关缓存功能。

 

教程主要讲述浏览器缓存和代理缓存,部分内容对于那些对网关缓存感兴趣的人也有用。

 

4 web缓存如何工作

所有的缓存都有一些列规则,用来决定在缓存有效的情况下,什么时候为表现层服务。一部分规则在协议(http1.0 http1.1)中设置,一部分由管理员设置。

通常来讲,包含下面的一些规则:

1、如果响应的头部信息中包含不需要缓存的设置,那就不需要缓存。

2、如果请求是验证方面的,或者是安全连接(https),不会被缓存。

3、在下列情况下,代表缓存中的一个内容是新鲜的(代表它可以在不访问原始服务器的情况下发送给客户端)

   3.1 包含expires设置,或者是age-controlling设置,并且还在保鲜期内。

   3.2 如果缓存的内容刚被表现层使用,而且它还没有被修改过。

新鲜的内容直接从缓存或者,不用去原始服务器获取。

4、如果表现层过期,将会访问原始服务器并且验证它,或者告诉缓存是否缓存的拷贝可用。

5、在下列情况,例如,从网络断开连接,缓存会提供旧的响应内容,而不会访问原始服务器。

如果响应中没有ETag or Last-Modified这些信息,也没有任何关于新鲜的明显信息,通常,不总是,将被认为不使用缓存。

新鲜度和验证的信息对于缓存的工作来说都是很重要内容,新鲜度的信息直接从缓存中获取,验证的信息保证在没有被修改的情况下,避免发送完整的内容。

 

6 构建一个有缓存意识的站点用到的技巧

除了刷新信息和验证,下面的技巧可以使你的站点更加缓存友好。

1、使用一致的url地址。这是一条关于缓存的黄金法则。如果你在不同的页面,对不同的用户,或者是不同的站点,提供相同的内容,应该使用相同的url地址。这是最容易,也是最有效的,使你的站点缓存友好的方式。例如:如果你使用“/index.html”在某个地方,那么请一直使用这个地址。

2、在不同的地方使用公用的图片库,及公用的元素。

3、对于缓存中不经常改变的图片和页面,使用Cache-Control: max-age,并且设计一个较大的值。

4、对于缓存中有规律的改变的内容,给max-age或者是expire设置适当的值。

5、如果一个资源(尤其是需要下载的文件)的内容发生了变化,可以重新命名这个资源。那样的话,你可以设置一个将来的过期时间,还可以确保提供了正确的版本。

6、不要改变那些没有变化的文件。如果你这么做,所有的文件都会有一个新Last-Modified日期,会导致缓存失效。例如:当你更新站点的时候,不要拷贝覆盖整个站点,只是替换那些变化了的文件就可以了。

7、尽量少用ssl,因为加密的页面不会缓存,只在你需要的时候使用,而且在ssl页面中少用图片。

8、使用REDbot检查你的网页,它可以帮助你应用这篇教程中的很多概念。

 

7 写有缓存意识的脚本

默认情况下,很多脚本不会返回验证(响应头中的Last-Modified or ETag),或者是刷新信息(Expires or Cache-Control)。同时很多脚本是动态的,就是说每次请求会返回不同的响应,

通常来说,如果一个脚本的产出,对于一段时间之后的相同请求,是可以重用的,它就应该可以缓存。如果脚本改变的内容依赖于url,它是可以缓存的;如果产出依赖于cookie,验证信息,或者是其他外部条件,那么就不要缓存它。

1、使得一个脚本缓存友好(性能更优)的最好办法是,当脚本变化的时候,把脚本的内容输出到一个普通文件。这样web服务就可以像对待其他web page一样对待它,使得你的工作更轻松。记住,只在脚本发生变化的时候,才写文件,这样Last-Modified中的时间才会保留下来。

2、另一个缓存脚本为有限的新鲜的办法是,设置age相关的header。尽管可以通过expires来做,不过最容易的办法还是用Cache-Control: max-age,这样可以使得在请求之后的一段时间保存新鲜。

3、如果你没有按照上面的方法做,你需要在脚本上生成一个验证,用来响应带有If-Modified-Since or If-None-Match的请求。可以通过解析http header来实现,如果没有修改,返回304 Not Modified响应。

4、不随便使用POST,对于post的响应不会被缓存;如果你使用get,缓存才会存储将来用到的信息。

5、不要在url中嵌入特殊的用户信息,除非嵌入的信息对用户来说是唯一的。

6、在响应头中生成Content-Length。这很容易做到,它允许在长连接中使用脚本的响应。允许客户端在一次tcp/ip连接中做多次响应,而不是每次请求都建立一个连接。使得你的站点访问更快。