Hunter的大杂烩 技术学习笔记

May 9, 2006

缓存友好的网页[zt]

Filed under: Linux — hunter @ 12:14 pm

翻译:ShiningRay @ Nirvana Studio

现在我们有很多HTTP缓存。他们存放你的页面多久呢?他们应该存放多久呢?RFC 2616(HTTP/1.1)指出了缓存必须遵循Expires和Cache-Control头——那么你的页面是否都有呢?

“在HTTP/1.1种的缓存的目的是为了在很多情况下消除发送请求的需要,同时在其他一些情况下消除发送完整的响应的需要。” RFC 2616

缓存友好页面的优点
“当缓存可以完全避免对原始服务器发送请求时,HTTP缓存的工作是最佳的。避免请求的主要机制是,针对原始服务器提供未来的一个确切的失效时间,表示一个响应可以被用来满足后续的请求。换句话说,一个缓存可以返回一个新的响应而不必先联系服务器。”RFC 2616

RFC写的时候是期望网页要包含失效期头的。如果谨慎地选择头中的失效时间,缓存可以不失去任何意义来提供存储了的页面。

当原始服务器不提供失效头时,缓存根据诸如“Last-Modified”之类的头来推断,猜测出一个合适的失效时间。与由了解页面内容以及更改频率的人设置的失效日期相比,推断的方法显然效率较低。

“由于推断的失效时间也许会降低语义透明度,应该被谨慎使用,同时我们鼓励原始服务器尽可能提供确切的失效时间。”RFC 2616

关于缓存的注意事项
HTTP/1.1标准(第13节)关于缓存有一个强制的要求:它要求他们提供语义的透明——返回一个缓存了的响应必须提供本来从原始服务器上获取的同样的数据;同时它提倡读取原始服务器和客户端所提供的新鲜度要求。

缓存必须传递由上游缓存或者是原始服务器提供的警告,而且如果提供了一个陈旧的响应,他们也必须加入警告。一个缓存可以在特定的情况下提供一个陈旧的响应,大部分情况下是如果缓存无法连接到原始服务器同时客户端声明它可以接受一个陈旧的响应。

如果一个缓存收到了针对一个陈旧页面的请求,它发送一个验证请求询问原始服务器页面是否已经更改。最常见的验证工具便是最后的更新时间。如果在一秒钟内存储了两次更改,Last-Modified将会不正确。因此,HTTP/1.1利用Entity Tag头提供了更加严格的验证。

最简便的协助缓存的方法是保持你的HTTP服务器上的时间精确且总是发送Date和Last-Modified头。

另外,要成为一个真正的缓存友好的站长,还要在你的页面中加入缓存头。

可用的缓存头
Expires头是最快捷最方便的解决方案。这个头声明了页面被认为不再可被缓存的时间,在这之后,任何保存了这个页面副本的缓存都应该联系原始服务器。语法是:

Expires:

例如:

Expires: Sun, 10 Feb 2002 16:00:00 GMT

若要标记一个响应为已经“已经过期”或者“不可缓存”,头则应该设置为发送响应的时间。若要标记一个响应为“永不过期”,则应该将头设置为未来的一年。

另一个头是Cache-Control。Cache-Control包括了这些元素:指明页面元素最大时限,他应该如何被缓存的,他如何被转换到另一个不同的媒介,以及他如何被存放在持久媒介中的。

本文使用Apache为例,设置头并在例子中详细讨论Cache-Control头。

在Apache中设置缓存头
主要的方法:Expires头
要使用Expires头,你需要运行在Apache 1.2或者更新的版本上,同时要启用 mod_expires 模块。去掉httpd.conf文件在“Dynamic Object Support”一节中的 expires_module 一行上的注释,然后重新编译Apache。

#

# Dynamic Shared Object (DSO) Support

#

# LoadModule cern_meta_module /usr/lib/apache/1.3/mod_cern_meta.so

LoadModule expires_module /usr/lib/apache/1.3/mod_expires.so

(如果你运行的是Apache 1.3或更新的版本,同时它已经配置为运行时加载模块,你可以编辑httpd.conf然后重新启动Apache而无需重新编译。)

mod_expires 基于三条指令来计算Expires头。这些指令可以应用于文档范围同时也可以在任何以下范围内使用:“server config”、“virutal host”、“directory”、或者“.htaccess”。

Expires指令有两种语法。其中一个有点难以阅读;它要你计算到失效为止用的秒数。幸运的是,这个模块同样可以读取一个更加人性化的语法。本文将解释较为可读的语法。

要用到的指令是:

ExpiresActive on|off

ExpiresDefault “ [plus] { }*”

ExpiresByType type/encoding “ [plus] { }*”

base 可以是以下其中之一:

access

now (等同于“access”)

modification

num 是一个整数值,单位是 type :

years

months

weeks

days

hours

minutes

seconds

如果你准备对一个服务器、虚拟主机或者是目录使用Expires指令,编辑 httpd.conf 文件并在所需的范围内加入以下指令。

# 包括任何其他你想要加入这一节的东西

ExpiresActive on

ExpiresByType image/gif “access plus 1 year”

ExpiresByType text/html “modification plus 2 days”

# ExpiresDefault “now plus 0 seconds”

ExpiresDefault “now plus 1 month”

如果你要在 .htaccess 文件中使用Expires头,那么你要先编辑httpd.conf 设置相应的目录的AllowOverride。Apache只会读取设置了“Indexes”覆盖的目录中的 .htaccess 。

# 针对使用.htaccess的目录,允许Indexes覆盖

# 包括任何其他你想要加入这一节的东西

AllowOverride Indexes

在相应目录里的 .htaccess 文件中加入Expires指令。站长可以编辑 .htaccess 文件而无需修改httpd.conf。

“.htaccess”方法的主要问题是Indexes覆盖,这样.htaccess 文件将给予站长更多的配置选项而非仅仅Expires头。这也许并不是系统管理员所期望的。

候选方法:Cache-Control 头
mod_cern_meta 允许文件级的控制,同时它也可以使用Cache-Control头(或任何其他头)。响应头是放在原始目录的子目录中,根据原始文件名所命名的一个文件。

去掉cern_meta_module 一行的注释并重新编译,和上一节中对expires_module 的一样。

在httpd.conf 文件中,打开MetaFiles on,将 MetaDirectory 设置为子目录名,同时把MetaSuffix设为头的文件的后缀名。

MetaFiles on

MetaDirectory .web

MetaSuffix .meta

使用这些值的话,文件 /var/www/www.example.org/index.html 将会以 /var/www/www.example.org/.web/index.html.meta. 为元文件。

任何有效的HTTP头都可以放在这些文件中。这提供了另一种使用Expires头的方式,同时它可以加入Cache-Control头。相应的Cache-Control头如下:

Cache-Control : max-age = [delta-seconds]

修改失效机制,将覆盖Expires头。Max-age隐含了Canche-Control: public。

Cache-Control : public

表示对象可以被存在缓存中。这是默认值。

Cache-Control : private

Cache-Control : private = [field-name]

表示对象(或指定字段)不能被保存在一个共享的缓存中同时是针对一个单独的用户的。它可以被保存在一个私有的缓存中。

Cache-Control : no-cache

Cache-Control : no-cache = [field-name]

表示对象(或者指定字段)可以被缓存,但不能直接给客户除非经过原始服务器的重新验证。

Cache-Control : no-store

表示条目不能存储在持久的存储媒介中,同时应该尽可能快地从非未定存储媒介中删除。

Cache-Control : no-transform

代理可以将数据从一个存储系统中转换到另外一个。这个指令表示(大多数)响应不能被转换。(RFC允许某些字段的转换,即使存在这个头)

Cache-Control : must-revalidate

Cache-Control : proxy-revalidate

强制代理重新验证该页面即使客户可以接受一个陈旧的响应。请在使用这些头之前阅读RFC,关于他们的使用有一些限制。

警告
HTTP/1.0有一个很小的缓存控制机制,仅能理解Pragma: no-cache头。使用HTTP/1.0的缓存将忽略Expires和Cache-Control头。

任何一个Cache-Control指令都不能保证隐私性或者数据的安全性。“private”和“no-store”指令可以为隐私性和安全性方面提供一些帮助,但是他们并不能用于替代身份验证和加密。

本文不能代替RFC。如果你要实现Cache-Control头,请阅读RFC来获取每个头的含义和限制的详细描述。

最后的话
缓存是Internet的现实问题同时它能让带宽的使用更加有效。你的客户也许是通过一个缓存来浏览你的页面的,有时候还会用多个缓存。给你的页面加上缓存头可以保护你的页面内容也可以让你的客户节省他们的带宽。

进一步阅读
RFC 2616:

第 13 节 (缓存)

第 14.9 节 (Cache-Control 头)

第 14.21 节 (Expires 头)

第 14.32 节 (Pragma: no-cache)如果你是与HTTP/1.0缓存交互的话这很重要

第 14.29 节 (Last-Modified) 是最常见的检验手段

第 3.11 节 (Entity Tags) 涵盖了额外的检验手段

Apache 用户手册: http://httpd.apache.org/

http://apache-server.com/tutorials/ATusing-htaccess.html

你的Web服务器的用户手册

Jennifer Vesperman 是《Essential CVS》一书的作者。她为O’Reilly Network、Linux Documentation Project撰稿,有时也为Linux.com。

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress