缓存入门教程

缓存入门教程


原文链接:https://www.mnot.net/cache_docs
以下为本人翻译,仅用于交流学习,版权归原作者所有,转载注明出处,请不要用于商业用途

这是一份资讯文档。尽管从技术本质上来说,它应该尽量让所涉及到的概念在现实里更易理解和易运用。所以,为了使文章更清晰易理解,我们把一些知识点简化和省略了。如果你对这篇文章中的细节有兴趣,请到文末的“参考文献与更多信息”部分查找。

  • 什么是Web缓存?人们为什么用它?
  • Web缓存的分类
    浏览器缓存
    代理缓存
  • Web缓存内容对我们没用么,为什么我们要帮他们?

  • Web 缓存如何工作
  • 如何控制(以及不控制)缓存
    HTML元标签 vs. HTTP头
    HTTP头指令 (为什么他们无法正常工作)
    使用HTTP 头部的Expires指令控制内容的及时性
    HTTP 头的Cache-Control指令
    验证器与验证
  • 创建一个带缓存的网站的注意事项

  • 编写带缓存的脚本
  • 常见问答
  • 实现注意事项— Web 服务器
  • 实现注意事项—服务端脚本
  • 参考文献与更多信息

什么是Web缓存?人们为什么用它?

Web缓存是存在一个或多个Web服务器(或者原始服务器)与一个或者多个客户端之间。它监视经过的请求,为自己保存响应数据的拷贝—就像HTML网页,图片和文件一样(统称为内容副本)。这时,如果有一个同样的URL请求过来,它就可以把已有的数据作为响应,而不是去原始服务器再一次请求数据。

为什么要用到Web缓存有2个原因:
• 降低延迟 — 由于请求更倾向于从缓存中而不是从原始服务器拿到合适的数据,所以它减少了获取和展示的时间。这也使得Web看起来响应更快。
• 减少了网络阻塞 — 由于内容被重用,它为客户端减少了宽带。而且如果他们要为网络阻塞付出费用,这可以为他们节约费用,也使得他们的带宽需求更低,更易于管理。

Web缓存的分类

  • 浏览器缓存
    如果你检查任何现代Web浏览器(比如Internet Explorer, Safari or Mozilla)的“选项”对话框,你会注意到有个“缓存”设置。它允许你在计算机硬盘上为自己留出一块区域存储你浏览过的内容。浏览器缓存通过非常简单的规则来工作。它在一个会话里保证内容副本是新的(也就是说在浏览器里当前调用里只出现一次)。
    当用户点击了“后退”按钮或者点击了一个链接去查看他已经看过的页面,这个时候缓存尤其有用。同样的,当你在你的网站使用一样的导航图片时,他会立即从浏览器缓存里取出来。

  • 代理缓存
    Web的代理缓存也是同样的规则,不过它的范围很大。这些代理用同样的方法为成百上千的用户服务,一些大公司和ISP服务商经常把代理缓存建在他们的防火墙上,或者直接作为标准设备(比如中介设备)。
    由于代理缓存不是客户端或者原始服务器的一部分,相反他们是在网络上,所以请求必须要以一定方式路由到他们。一种方法是通过你的浏览器的手动代理设置告诉他应该用哪个代理。另一种方法是使用拦截。拦截代理通过使用潜在的网络把请求直接重定向到他自己,所以客户端不需要专门配置,甚至根本不知道他们的存在。
    代理缓存是共享缓存的一种,由于他们具有降低延迟和减少网络阻塞的优点,所以有大量用户使用他们而不仅仅是一个。

  • 网关缓存
    类似“反向代理缓存”或者“代理项缓存”,网关缓存也是中间机构,不过他们被网络管理员部署并不是用来节约带宽,而常常是被网站管理员用来使他们的网站更具扩展性,可靠性和更好的性能。
    请求可以通过很多种方法被路由到网关缓存,但通常来说,通过使用某些形式的负载均衡,可以使得他们看起来像是从原始服务器到客户端一样。
    内容分发网络服务商(CDNs) 通过互联网(或者其中一部分)发布网关缓存,以及把他们卖给对此感兴趣的网站。比如像Speedera 和 Akamai这种CDN。
    尽管这份教程中的一些内容很适合那些对网关缓存感兴趣的人,但是我们主要焦点还是集中在浏览器和代理缓存。

Web缓存对我们没用吗?我为什么要帮他们?

Web缓存技术是互联网上被误解最多的技术之一。网站管理员尤其怕失去对他们网站的控制,因为一个代理缓存能隐藏真实的用户,使得他们很难知道谁在使用网站。

很不幸的是,即使Web缓存不存在,对于他们想得到一张精确的关于用户如何看到他们网站的图表来说,在网络上仍然有很多变数。如果你对此很关心,这份教程能指导你如何得到你需要的统计数据而不需要在你的网站上加上非友好的缓存。

另一个关心的是缓存会把那些过期的或者旧的内容也缓存化。不管怎样,这份教程能教你如何配置服务器以此来控制你的内容如何被缓存。

CDN 是一种非常有意思的发展技术,因为和许多代理缓存不同,他们的网关缓存会和被缓存的网站中感兴趣的部分进行同步,所以这些问题将不会存在。然而,即使你使用CDN,你仍然需要考虑他们会被下层的代理或者浏览器缓存化。

另一方面,如果你能把你的网站设计好,缓存能使你的网站加载更快,在你的服务器和互联网连接上节约加载次数。这种差异很戏剧化,一个网站如果很难被缓存化,那么可能在加载的时候会多花几秒钟,相比之下,如果利用了缓存的优点则看起来会变得非常快。用户更喜欢加载速度快的网站,而且会经常访问。

想想看,许多大型的互联网公司为了使得他们的用户访问速度更快,在全世界花费数百万英镑建立服务器中心来备份他们的内容。对你来说,缓存也是这样,而且更贴近用户。最好的是,是你根本不需要为此付费。

实际上,不管你喜不喜欢,代理缓存和浏览器缓存都会被使用。如果你没有正确的配置你的网站缓存的策略,它会用缓存管理员决定好的默认方式来缓存化。

Web 缓存如何工作

所有的缓存都有一系列的规则,基于此,他们会决定什么时候从可用的缓存里取出来为当前内容副本服务。其中一些规则是被写在协议里(比如HTTP1.0和1.1),另外的一些则被缓存的管理员制定(浏览器缓存的用户或者代理管理员)。

一般说来,接下来介绍的都是最常用的(别担心你不知道细节,后面会解释):
1. 如果响应头说了不要缓存,它就不会缓存任何内容。
2. 如果请求是安全验证的或者安全的,它不会被缓存化(i.e., HTTPS)。
3. 当前内容已缓存且被认为是最新的(也就是说发给客户的时候不需要去原始服务器验证),如果:
• 它的头有过期时间或者其他年龄控制的参数设置,并且仍然在有效期内, 或者
• 如果最近这个缓存和当前内容一致,并且在相对长时间之前被修改过。.
当前新内容是从缓存里直接提取的,而不用从原始服务器那里去验证。
4. 如果当前内容是旧数据,原始服务器就会被要求验证它,或者告诉缓存它拥有的拷贝是否有效。
5. 在某些情况下—比如,网络连接断开—缓存可以作为过时的响应而不用去原始服务器验证。

如果在一个响应里没有验证者(一个ETag或者Last-Modified头)出现,而且它没有任何明确的新内容,它通常-但不总是-被认为不可缓存化。

总之,新鲜度和验证是缓存与内容正常工作时最重要的方法。一个已被验证过的内容在它还未改变的时候会避免将整个内容发出去,此时,它可以立即从缓存里拿到新内容。

如何控制(或不控制)缓存

有一些服务器工具,网站设计者和网站管理员可以用它们来对缓存进行微调以使其能更好服务网站。对于服务器的配置来说,或许还需要一些特别手段,不过结果是值得的。关于使用这些工具的具体细节,可以看后边的“实现”部分。

HTML元标签和HTTP头

HTML的作者可以在文件的区域加上标签来描述它的属性。这些元标签 通常被认定可以标记一份文档在某一个时间是不可缓存的,或者过期的。

元标签易于使用,但却低效。因为仅有少数浏览器缓存而不是代理缓存(从来不在文档里读取HTML)支持它。尽管它会尝试在网页里加入指令:no-cache元标签,但是用它来维持新数据却没必要。

如果你的网站在ISP或者数据中心托管,他们不会让你设置任何HTTP头(比如Expires 或者Cache-Control),这的确很恼人。所以这些工具对于你的工作就很有必要了。

另一方面,真正的HTTP头参数可以给你很多关于浏览器缓存和代理缓存如何处理内容副本的控制权。这些在通常由网站服务器自动生成的HTML里无法看到。然而,依赖你使用的服务器,你可以在某种程度上控制他们。下面,你会看到哪些HTTP头是值得关注的,以及如何在你的网站上运用。

HTTP 头由服务器在HTML之前发送,而且仅能被浏览器或者任何一个中间缓存看到。通常HTTP 1.1的响应头看起来像这样:

HTTP/1.1 200 OK
Date: Fri, 30 Oct 1998 13:19:41 GMT
Server: Apache/1.3.3 (Unix)
Cache-Control: max-age=3600, must-revalidate
Expires: Fri, 30 Oct 1998 14:19:41 GMT
Last-Modified: Mon, 29 Jun 1998 02:28:12 GMT
ETag: "3e86-410-3596fbbc"
Content-Length: 1040
Content-Type: text/html

HTTP头指令 (为何他们不能正常工作)

HTML会紧跟着这些头,并且由空白行分开。关于如何设置HTTP头,可以看“实现”部分。
很多人认为给内容副本的HTTP头指令:no-cache 赋值会使得它不能被缓存。这并不正确,HTTP规范里并没有任何一个响应头指令的设置指南。相反,请求头指令(浏览器发送给服务端)倒是被讨论过。尽管只有少数缓存会遵守头部参数,但大多数都不会,而且它没有任何作用,他们用下面的头参数替代。

使用HTTP 头的Expires指令控制内容的及时性

HTTP头的Expires 指令是控制缓存最基本的方式,它告知所有缓存它所涉及的内容副本会保持多长有效时间。在时间过了之后,缓存总会去和原始服务器检查看是否当前文档内容已被改变。几乎所有的缓存都支持Expires 头参数。

很多网站服务器允许你用各种方法设置响应头的Expires 指令。一般来说,他们允许设置绝对的过期时间,它基于最后一次客户端接收到的内容的时间(最后一次访问时间),或者基于此文档在你的服务器上最后一次被改变的时间(最后一次被修改时间)。

Expires 指令对静态文件的缓存化(比如导航栏和按钮)尤其有用。因为他们不经常改变,你可以设置一个很长的过期时间,让你的网站更快的响应给用户。同样,对于那些频繁改变的文件的缓存控制也很有用。举个例子,如果你每天早上6点更新了一个新闻页面,你可以设置内容在这个时间点过期,这样缓存就知道什么时候去获取一个最新的拷贝,而不需要用户手动点击“重加载”。

在Expires 指令中唯一正确的值是HTTP日期,其他任何值都会被作为是“过去的”,这样当前内容就是不可缓存的。记住,HTTP日期的是格林威治时间(GMT),而不是本地时间。

举个例子:

Expires: Fri, 30 Oct 1998 14:19:41 GMT

很重要的一点,如果你使用Expires头指令,必须确保你的网站服务器时钟是正确的。一种方法是用Network Time Protocol(NTP),询问你本地系统管理员可以获取更多信息。

尽管这个Expires 指令很有用,但它仍然有些限制。首先,由于涉及到日期,网站服务器上的时钟与缓存必须是同步的。如果他们时间不同,预期的结果将不会实现,而且缓存也会错误的将过期内容视作新的。

另一个关于Expires 的问题是,你会很容易忘记你曾经给内容设置了过期时间,它是一个具体时间,如果在这个时间到来之前你还没有更新Expires 时间,此后每一个请求都会转到你的网站服务器,这增加了加载和延迟。

HTTP头的Cache-Control指令

HTTP1.1介绍了一种新类型的头部参数,Cache-Control响应头,给了网站发布者更多的对内容的控制权,以及弥补Expires参数的缺点。

可用的Cache-Control响应头参数包括:
• max-age=[seconds] —指定内容副本保持最新的最大时间。与Expires类似,这个指令和请求的时间有关,而不是绝对的时间。[seconds]表示你希望请求的内容副本保持多少时间的最新。
• s-maxage=[seconds] —和max-age类似,不同的是,它只对共享(如代理)缓存有效。
• public —标记已安全验证的响应可以被缓存。通常,如果HTTP安全验证是必须的,响应会自动变成private。
• private —仅允许指定的单个用户的缓存存储响应数据,共享(如代理)缓存不允许。
• no-cache —任何时刻在释放缓存拷贝之前,会强制缓存将请求提交给原始服务器去验证。这对于保证遵循授权规则(和public结合),或者维护严格的实时性很有用,而不需要牺牲缓存的所有优点。
• no-store —强制缓存在任何情况下都不要去存储内容副本的拷贝。
• must-revalidate —要求缓存内容必须和你提供的关于内容副本的新内容保持一致。 HTTP允许缓存内容在特殊条件下为过时的当前内容服务。通过指定这个头部,你可以强制缓存必须严格遵守你的规则。
• proxy-revalidate —和must-revalidate一样,不同的是它只对代理缓存有效。
例如:
Cache-Control: max-age=3600, must-revalidate

当 Cache-Control 和Expires都存在时,Cache-Control会优先起作用。如果你打算用 Cache-Control头,你应该去HTTP1.1里看更详细的文档。可以参照“参考文献与更多信息”。

验证器与验证

在“Web缓存如何工作”里,我们说在内容副本被改变时,服务器和缓存可以通过验证来进行通信。通过这种方式,在当本地已经有一个备份时,缓存避免了去下载整个内容,但它仍然不确定内容是否是最新的。

验证器非常重要,如果一个验证者都没有,在没有任何新信息(Expires 或者 Cache-Control)可用时,缓存根本不会存储当前内容。

最常用的验证器是这个文档最后一次修改时间,用Last-Modified头表示。当一个缓存已经保存了包含Last-Modified头的当前内容,它就可以借助这个头参数并用一个带有If-Modified-Since的请求去服务器询问当前内容在上一次被访问后是否已被改变。

HTTP1.1介绍了一种新的验证器,叫做ETag。ETag是一种唯一标识符,由服务器产生并每次都会被内容副本改变。由于服务器控制了ETag的生成,当用If-None-Match请求,并且内容都一致的情况下,缓存能确保ETag是否匹配。

几乎所有的缓存使用Last-Modified时间作为验证器,ETag验证也渐渐变得流行。

大多数现代浏览器会都会生成ETag和Last-Modified头自动作为静态内容(如文件)的验证器,你不需要做任何操作。然而,他们还没有足够能力为动态内容(比如CGI,ASP或者数据库)生成ETag和Last-Modified头,见“编写支持缓存脚本”。

创建一个支持缓存网站的注意事项

除了使用新内容和验证方式外,你还可以通过很多种方式使你的网站更友好的缓存。
• 使用一致的URL —这是缓存的金科玉律。如果你在不同的页面为相同的内容提供服务,对于不同的用户,或者来自不同的网站,应该使用同样的网址。这是一种最容易也最有效的使你的网站友好缓存的方式。比如,如果你在你的HTML中用“/index.html”引用另一个HTML,它总是使用这种方式来缓存。
• 使用通用的图片库 和其他的元素库,这样可以从不同的地方引用到他们。
• 让缓存内容保存不经常改变的图片和页面, 通过使用Cache-Control: max-age 头,并设置一个大的值。
• 使缓存内容定期的识别已更新的页面,通过指定一个合适的max-age或者过期时间。
• 如果来源(尤其是一个可下载的文件)改变了,修改其名字。 用这种方式,你可以使其在未来很长时间才过期,并仍然能保证正确的版本可用,而链接它的页面是唯一一个需要短期过期时间的。
• 不要改变不需要的文件。 如果你这样做了,会导致所有内容的 Last-Modified 日期变短并且是错误的。比如,当更新网站,不要拷贝整个网站,而只移动修改过的文件。
• 仅当需要的时候才用cookies — cookies很难被缓存,并且在很多情况下都不需要。如果你必须要用它,请限制在动态页面使用。
• 减少SSL的使用 — 因为加密的网页不会被共享缓存保存,仅仅当你必须要用,而且在SSL页面很少用到图片的时候才使用。
• 使用 REDbot检查你的网页 — 它能帮你应用此文中的很多概念。

编写支持缓存的脚本

默认的,许多脚本并不会返回验证器(Last-Modified 或者 ETag 响应头)或者新内容(Expires 或 Cache-Control)。然而有些脚本是真正的动态(意思是对每个请求返回不同的响应)的,许多网址(比如搜索引擎和数据库驱动网址)能从友好缓存里获得益处。

一般来说,对于接下来一段时间内(分钟或者天数)的同一个请求,如果一个脚本产生的输出是可以重复利用的,它就应该是可缓存的。如果这个脚本的改变仅仅依赖于URL,它也是可缓存的,如果输出依赖于cookie,安全验证信息或者其他外部的准则,它就不应该被缓存。

• 使脚本“顺利缓存”(就像性能越好一样)的最好的方法是一旦它发生变化就把内容转储到空白文件。此时网站服务器会像对待其他网页一样对待它,比如产生和使用验证器,让你生活更美好。请记住只有当它变化时才写入文件,所以Last-Modified时间需要保存。
• 另一种在有限的方法里使脚本可缓存的方法是去设置一个“年龄相关的”头,它在之后很长时间内都是有实用性的。这个可以用Expires实现,甚至用Cache-Control: max-age更容易实现,在请求之后很长时间内它能使得请求继续有效。
• 如果你没有这么做,那么你需要让脚本产生一个验证器,并让它响应 If-Modified-Since 和/或者If-None-Match请求。通过解析HTTP头可以实现,合适的时候可以用304 Not Modified响应。不幸的是,它并不重要。
一些其他的建议:
• 不要使用POST 除非有合适场景。对POST方法的响应内容,大多数缓存都不支持。如果你使用路径或者查询(通过GET)发送信息,缓存可以为之后的请求保存此信息。
• 不要将指定用户的信息附加到URL里, 除非这个内容完全只由这个唯一用户产生。
• 不要计算来自同一个域名的同一个用户的所有请求的数量, 因为缓存总是工作在一起。
• 生成Content-Length 响应头 。这很容易办到,而且能使你的脚本的响应在持久连接里也能用到。这允许客户端在一个TCP/IP连接上去请求多个内容而不用为每个请求都建立一个连接。这能使你的网站更快。

常见问题解答

  • 使其能缓存的最重要的事情是什么?
    一个好的策略是去找出最受欢迎,最大的内容(尤其是图片),然后让他们首先工作起来。
  • 我如何能使我的页面和缓存一样快?
    许多可缓存的内容都都有一个很长的刷新时间设置。验证的确能降低内容显示的时间,但是缓存仍然要和原始服务器保持联系以便于查看是否有新内容。如果缓存已经知道了内容是最新的,它会尽可能快的直接为内容服务。
  • 我知道缓存很重要,但是我需要统计有多少人访问我的页面!
    如果你必须要知道一个页面被访问的任何时间,在页面上放置一个小的元素 (或者页面本身),并且给它一个合适的头参数使它不能被缓存。比如,你可以在每个页面引用一个1x1大小的透明的不可缓存的图片。 Referer头包含了一些关于哪些页面调用了它信息。
    我们知道其实这并不会给你关于你的用户真实的统计数据,而且还对互联网和你的用户产生了不友好,因为它产生了不必要的网络阻塞,并迫使用户去等待那些不能缓存的内容下载。想要了解更多,可以看references.中的“Interpreting Access Statistics”。

  • 我如何看到一个内容的HTTP头?
    许多网络浏览器可以让你在“网页信息”里或类似接口查看Expires 和Last-Modified头 。如果可能的话,它会给你提供非常详细的关于这个页面的目录以及任何和它关联的内容(比如图片)。
    为了看内容的所有头,你可以用Telnet工具手动的连接到网站服务器。
    你需要输入端口(默认80)到不同的区域。或者你需要连接到 www.example.com:80 或者www.example.com 80 (注意空格)。可以查看你的Telnet客户端的文档。
    一旦你打开了一个网站的连接,就可以输入内容的请求。比如,如果想看到http://www.example.com/foo.html的头,连接到www.example.com, 端口80, 输入:

GET /foo.html HTTP/1.1 [return]
Host: www.example.com [return][return]

每当看到[return]的时候按下返回键,在最后确保按2次。它会打印头信息以及所有的内容。如果只想看到头,请用HEAD代替GET。

  • 我的页面是密码保护的,代理缓存如何处理他们?
    默认上,被HTTP安全认证保护的页面是被认为私有的,他们不会被代理缓存保存。然而,你可以使用Cache-Control: public 头使得安全认证的页面公开,只要遵循HTTP1.1的缓存内容允许他们被缓存。
    如果你想要这种对每个用户仍然是需要安全认证的网页可缓存,可以联合 Cache-Control: public 和no-cache头来实现。它告诉缓存在把内容从缓存里移除前必须把客户的安全认证信息提交到原始服务器。就像这样:
    Cache-Control: public, no-cache
    不论它有没有用,这都是减少安全验证使用的最好的方法。比如,如果你的图片不是敏感的,把它放到一个隔离的文件夹下,配置你的服务器使其不要对图片强制进行安全验证。这样,这些图片就会自然而然的被缓存化。

  • 如果用户通过缓存访问我的网站,我要担心安全问题么?
    代理缓存不支持(或解密)SSL网页,所以你不用担心这个。然而,由于缓存内容保存经过他们的非SSL请求和URL地址,你应该要警惕不安全的网站。一个不怀好意的管理员可以肆意得到很多他们用户的信息,尤其URL里。
    实际上,在网络上,任何一个服务器和客户端之间的管理员都可以拿到这种类型的信息。一个实际的问题是当CGI脚本把用户名和密码加到URL里,这将导致其他人很容易找到和使用他们的登录信息。
    如果你对Web安全环境问题有些了解的话,你就不会对代理缓存有任何惊讶。

  • 我正在寻找一个整合的Web发布解决方案,哪一种是支持缓存的?
    这是变化多端的。通常来说,解决方案越复杂,越难支持缓存。最坏的情况是动态生成所有内容并且不提供验证器,他们根本不会被缓存。向你的技术供应商人员寻求更多信息,也可以看看下面的“Implementation notes”。

  • 我的图片一个月后过期,但是我现在打算在缓存里修改他们!
    Expires头不能被跳过,除非缓存(浏览器或者代理)超过限制并且必须删除内容副本,这时缓存备份将无用。
    最有效的方法是改变到他们的所有连接,也就是说,完整的新内容将会从原始服务器加载一遍。记住,任何链接到这个内容的页面也会被缓存。因为这个,当要维持指向到它的HTML网页时,最好把静态图片和相似的内容完整缓存。
    如果你想从指定的缓存里重新加载当前内容,你可以在使用缓存时强制重新加载(在Firefox,通过指定指令:no-cache请求头,再点击“重新加载”时,同时按下shift),或者,你可以让缓存管理员通过他们的接口删除内容。

  • 我运行了一个网站域名服务,如何让我的用户发布“友好缓存”网页?
    如果你用的是Apache,可以考虑允许他们用.htaccess文件并提供合适的文档。
    另一方面,你可以为每个虚拟服务器事先建立一块区域用于各种不同的缓存属性。比如,你可以指定/cache-1m目录缓存首次访问后一个月内的数据。指定/no-cache 区域为那些头部参数要求缓存不去保存内容副本提供服务。
    不论你有没有办法做到,在缓存方面最好是让你的大型客户首先能正常工作。对于大容量网站来说,节约(比如带宽,服务器负载)都是有必要的。

  • 我已经将我的页面标记为可缓存,但是我的浏览器在每次请求的时候都会持续请求页面,我如何强制缓存去保存当前内容?
    缓存不需要保持当前内容并重复使用,他们仅需要在某些情况下不要保存和使用。所有的缓存都会基于大小,类型(比如图片vs html),或者需要留下多大空间来保存本地备份来决定哪种内容会保存。你的内容在和其他更流行的,更大的内容相比,也许被认为不值得保存。
    一些缓存确实会允许他们的管理员按照重要程度来决定哪种内容应该被保存,另外的一些允许内容被缓存控制,这样他们在任何时刻都是可用的。

实现注意事项— Web 服务器

一般来说,不管你选择什么Web服务器,最好选择最新版本。不仅因为他们可能包含更多“友好缓存”的特点,也通常有重要的安全和性能提升。
Apache HTTP Server
Apache 使用可选的模块来包含头,包括Expires and Cache-Control。在1.2及其更新版本里这2者都是可用的。

尽管在发布里包含了这些模块,但它不是默认编译好的,需要手动编译到Apache里。为了找出在你的服务器里这些模块是否可用,找到httpd二进制包然后运行httpd –l,它会打印出一个可用模块(注意这里仅列出了已被编译的模块,在之后的Apache版本里,使用httpd –M 去动态引入已加载的模块)的列表。我们要找的模块就是expires_module 和headers_module。

如果它不可用,此时你拥有管理员权限,就可以重新编译Apache引入他们。实现方式包括在配置文件里合适的地方去掉注释行,或者用-enable-module=expires and -enable-module=headers 参数去配置。请在Apache发行包里查阅INSTALL文件。

一旦你有一个带有合适模块的Apache,你可以用mod_expires去指定内容副本应该在什么时候过期,同样方式可以用在.htaccess文件或者服务器的access.conf文件。你可以依据访问或者修改时间来指定过期,并且把它应用到一个文件类型或作为默认。看module documentation 可以获取更多信息,当遇到问题还可以咨询当地Apache专家。

为了应用Cache-Control 头,你需要使用mod_headers 模块,它允许你为每个资源指定任意一个HTTP头。可以看the mod_headers documentation。

这有个.htaccess文件的例子描述了一些头的用法。

.htaccess 文件允许web发布者使用仅在配置文件里出现的通用的命令行。它对当前目录的内容以及子目录内容会起作用。如果可能可以咨询你的服务器管理员。

### activate mod_expires
ExpiresActive On
### Expire .gif's 1 month from when they're accessed
ExpiresByType image/gif A2592000
### Expire everything else 1 day from when it's last modified
### (this uses the Alternative syntax)
ExpiresDefault "modification plus 1 day"
### Apply a Cache-Control header to index.html
<Files index.html>
Header append Cache-Control "public, must-revalidate"
</Files>

mod_expires会在合适的时机自动的计算和插入一个Cache-Control:max-age头。
Apache 2的配置和1.3的配置非常相似,可以查看2.2的 mod_expires 和 mod_headers 文档获取更多信息。

Microsoft IIS
Microsoft’s 因特网信息服务器可以非常容易的用一个灵活的方法设置头。注意这仅对版本4有用,而且仅运行在NT服务器上。

为了给网站的大部分区域指定头,可以在管理员工具接口里选择它,并带来它的属性值。在选择了HTTP头选项卡后,你应该查看2处感兴趣的区域,Enable Content Expiration 和Custom HTTP 头。第一种不用说了,第二种可以用来应用Cache-Control头。

关于在Active Server Pages中的头设置信息,可以查看下面的ASP部分,它也可以通过ISAPI模块来设置头,想获取更多细节请查看MSDN网站。

Netscape/iPlanet Enterprise Server
在3.6版本中,Enterprise Server不会提供任何显式的方法去设置Expires头。然而,从3.0开始他已被HTTP1.1特性所支持。这意味着HTTP1.1缓存(代理和浏览器)会充分利用你设置的Cache-Control的优点。

为了使用Cache-Control头,可以在服务器上选择Content Management 或者 Cache Control Directives。这时,使用Resource Picker,选择你想设置头的目录。设置好之后,点击“OK”。想获取更多请看NES manual。

实现注意事项—服务端脚本

请注意,在Web服务器上设置HTTP头比用脚本语言设置容易得多。你可以两个都试试。

由于服务端脚本主要都是在动态内容上,对于很容易缓存的页面来说设置头是无用的,即使这个内容可以被缓存。如果你的内容经常改变,但不是每个页面都用到它,你可以设置一个Cache-Control: max-age 头,大部分用户在一个相对短的时间内可以重复访问这个页面。比如,当用户点击“后退”按钮,如果这里没有任何一个对可用新内容的验证器,他们必须等待页面从服务器重新下载直到能看到它。

CGI
CGI脚本是生成内容最流行的方式。你可以很容易地在发送实体内容之前把它追加到HTTP响应头里。大部分CGI实现已经需要你在Content-Type头里用这种方式。比如,在Perl里:

#!/usr/bin/perl
print "Content-type: text/html\n";
print "Expires: Thu, 29 Oct 1998 17:04:19 GMT\n";
print "\n";
### the content body follows...

因为都是文本,你可以很容易的用内置函数生成Expires和其他有关日期的头。甚至用 Cache-Control: max-age也一样简单。

print "Cache-Control: max-age=600\n";

这可以在请求后使脚本缓存10分钟,因此如果用户点击“后退”按钮,它不需要重新提交请求。

CGI规范也规定在脚本环境里用户发送的请求是可用的,每个头都会事先在名字前加上‘HTTP_’,所以,如果一个客户发送了一个If-Modified-Since请求,会以 HTTP_IF_MODIFIED_SINCE来显示。

也可以查看cgi_buffer 库,它使用同一个库为Perl和Python CGI自动处理ETag生成和验证,Content-Length 生成和压缩编码内容。Python版本也可以用来包围任意的CGI脚本。

Server Side Includes
SSI (经常用.shtml来做扩展名)是一种web发布者可以得到动态内容并传给页面的首要方法之一。通过使用页面的特殊标签,一种有限的HTML脚本形式是可用的。

大部分SSI实现都不会设置验证器,而且这种也是不可缓存的。然而,Apache的实现的确允许用户联合XbitHack 指令并通过在合适的文件上设置组可执行权限去指定哪个SSI文件能被缓存。查看更多信息请看mod_include documentation。

PHP
PHP 是一种服务端脚本语言,它内置到服务器内部,能把脚本内嵌到网页的HTML中,就像SSI,但是却有更多选项。PHP可以像CGI脚本一样用于任何网站服务器(Unix或Windows),或者作为Apache模块。

默认上,被PHP处理的内容,不会分配验证器,也因此不会被缓存。然而,开发者可以通过使用header()函数设置HTTP头。

举个例子,下面这种会创建一个未来三天的Cache-Control头以及Expires头:

<?php
 Header("Cache-Control: must-revalidate");

 $offset = 60 * 60 * 24 * 3;
 $ExpStr = "Expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
 Header($ExpStr);
?>

记住Header() 函数必须先于其他出现。

就像你看到的,你需要为Expires头手动创建HTTP日期,PHP没有提供一个函数为你做这个(尽管最近几个版本已经变得容易,查看 PHP’s date documentation)。当然设置一个Cache-Control: max-age头也很容易,它适合大多数场景。

想要了解更多,请查看manual entry for header.

也可以看 cgi_buffer 库,它可以用同一个库为PHP脚本自动处理ETag的生成和验证, Content-Length 的生成并压缩编码后的内容。

Cold Fusion
Cold Fusion, Macromedia 出品,是一个商业的服务端脚本引擎,支持Windows,Linux和Unix上的网站服务器。

Cold Fusion,通过使用CFHEADER 脚本,使得设置任意HTTP头相对很容易。不幸的是,下面他们一个设置Expires头例子,是误导的。

<CFHEADER NAME="Expires" VALUE="#Now()#">

如你所想,它不能正常工作,因为时间没有转换成HTTP合法的日期,而是打印Cold Fusion的Date/Time对象作为内容。大多客户端会忽略掉这种值,或者转成默认值,例如January 1, 1970 。

然而,Cold Fusion的确提供了一个能处理这种情况的日期格式化函数,GetHttpTimeString 。GetHttpTimeString 和DateAdd 一起使用可以很容易设置Expires日期,这里我们设置一个头来声明当前内容在一个月后过期:

<cfheader name="Expires" 
  value="#GetHttpTimeString(DateAdd('m', 1, Now()))#">

你也可以用CFHEADER 标签去设置Cache-Control: max-age以及其他头。

请记住,在经过一些Cold Fusion发布的网站(比如CGI),网站服务端的头会被过滤掉,通过在服务端设置头而不是在Cold Fusion来检查它并确定是否要把它当做优点。

ASP and ASP.NET

当在ASP里设置HTTP头时,确保响应方法调用在任何HTML生成之前,或者使用Response.Buffer 去缓存输出。同时注意IIS的一些版本会设置Cache-Control: private头作为ASP的默认值,要被共享缓存支持必须声明为public。

Active Server Pages, 它编译在IIS里,对于其他网站服务器也是可用的,它也允许你去设置HTTP头。比如设置过期时间,你可以用Response对象的属性来实现。

<% Response.Expires=1440 %>

从请求里给内容副本指定几分钟的过期时间。Cache-Control 头看起来像这样:

<% Response.CacheControl="public" %>

在ASP.NET里,Response.Expires被标记为过时,合适的办法是用Response.Cache去设置缓存相关的头 。

Response.Cache.SetExpires ( DateTime.Now.AddMinutes ( 60 ) ) ;
Response.Cache.SetCacheability ( HttpCacheability.Public ) ;

参考文献与更多信息

HTTP 1.1 规范
这个HTTP 1.1 规范对于标记网页可缓存有更多扩展,也是实现协议的权威指南。看13, 14.9, 14.21, and 14.25部分。

Web-Caching.com
一个非常棒的关于缓存概念的介绍,链接了其他在线资源。

On Interpreting Access Statistics
Jeff Goldberg的一个关于你为什么不能依赖访问统计和命中计数的有益的演说。

REDbot
诊断HTTP资源来决定他们是如何跟网站缓存交互的,以及他们通常怎样使用协议。

cgi_buffer Library
单行的包括Perl CGI,Python CGI和PHP脚本,并能正确的自动处理ETag生成和验证,Content-Length生成和压缩已编码内容。这个Python版本也能用于包围任何CGI脚本。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值