首先简单介绍下 apache 的 expires 模块,详细的 apache expires 介绍可以点这里:http://www.laoono.com/s-db/31.html。这个模块控制服务器应答时的 Expires 头内容和 Cache-Control 头的 max-age 值,如果同时设置了 cache-control 和 expires,cache-control 会覆盖 expires, 所以一般只要设置 cache-control 就好了。

有效期 (expiration date) 可以设置为相对于源文件的最后修改时刻或者客户端的访问时刻。这些 HTTP 头向客户端表明了文档的有效性和持久性。如果有缓存,文档就可以从缓存 (除已经过期) 而不是从服务器读取。接着,客户端考察缓存中的副本,看看是否过期或者失效,以决定是否必须从服务器获得更新。

_ueditor_page_break_tag_Apache 的 mod_cern_meta 模块允许文件级 Http 响应头部的控制,同时它也可以Cache-Control 头(或任何其他头)。响应头文件是放在原始目录的子目录中,根据原始文件名所命名的一个文件。具体用法请参阅 Apache 的官方网站。其中 Cache-Control : max-age 表示失效日期。如果没有启动 mod_cern_meta 模,Apache 服务器会把 Expires 字段中的日期换算成以秒为单位的一个 delta 值,赋值给 max-age。如果启动 mod_cern_meta 模块,并且配置了 max-age 值,Apache 会将这个覆盖 Expires 字段。同时,max-age 隐含了 Canche-Control: public。这样浏览器接受到的 Cache-Control : max-age 和 Expires 值就是一致的。


apache 的 expires模块配置规则如下:

ExpiresActive on|off
ExpiresDefault 
ExpiresByType type/encoding 

1. 其中 为 M 或者 A

M => Expires Header 显示文件将在此文件的修改时间 +后超时

A => Expires Header 显示文件将在此文件的访问时间 +后超时

需要注意的是 和 seconds 之间没有空格。

如果使用”M”,所有当前缓存中的文档副本都将在同一时刻过期,这个可能对定期更新的 URL(比如位于同一位置的每周通告)很有好处。

如果使用”A”,则每个客户端所得到的有效期是不一样的,这个可能对那些几乎不更新的图片文件很有好处,特别是对于一组都引用了相同图片的相关文档。

2.必须为一整数

例如:对于每小时自动生成的文件来说可以设置 1 小时过期

ExpiresDefault M3600

例如:apache 的 expires 模块根据类型设定不同的过期时间

ExpiresByType text/html A604800        # 1 周
ExpiresByType image/gif A2592000       # 一个月
ExpiresActive On|Off                   # 设置来针对某目录进行开启 | 关闭。

还有更人性化一点的写法:

ExpiresDefault " [plus] { }*"
ExpiresByTypeDefault type/encoding " [plus] { }*"

其中
1. 为:
access

now 等于 access
modification

2.plus 是可选的

3.必须为整数

4.为:

years/months/weeks/days/hours/minutes/seconds

例如:要使文档在访问后一个月过期,三种写法:

ExpiresDefault "access plus 1 month"
ExpiresDefault "access plus 4 weeks"
ExpiresDeafult "access plus 30 days"

或者更细微的写法:

ExpiresByType text/html "access plus 1 month 15 days 2 hours"
ExpiresByTypes image/gif "modification plus 5 hours 3 minutes"

实现方式:
1、首先判断配置 A/M 或者人性话的写法也转成 格式。根据 A 或者 M 来取 base 时间

1)如果是 M,base 时间为 r->finfo.mtime(即文件的修改时间),如果文件不存在本地,返回(但不报错)。

2)如果是 A,base 时间为 r->request_time. 这个时间已经存在 request 结构中;

注意:这里的 r->request_time 是来自客户端的 Request 时刻。这样会导致 2 个问题:

1)客户端时间如果和服务器时间不一致的话,那么很可能我们期望的的 expires 效果会失去;

2) 每个客户端到服务器请求文件时的 request_time 都不一样,那么如果设置 A,则客户端将陆陆续续的过期,如果设置 M,那么所有的客户端都以服务器端文件的修改时间为基准,将在同一时间过期;(这特别适合于定时更新的文件,比如新闻网 页),这样在过期时刻会引起巨大浪涌。

2、根据配置中的 seconds 得到 addtional 时间;

3、过期时间 expires = base + additional;

4、生成 Cache-Control:max-age 头(Header),max-age=expires - t->request_time;

ps: 其实这里有点多余?
expires = base + additional
base = r->request_time
max-age = expires - t->request_time = (base + additional) - r->request_time = addtional

但是这是错误的。因为过期时间的从 r->request_time 算起到 expires 时间结束。如果设置为 M 那么 max-age 就不等于 addtional。比如:文件在 3 小时前修改到现在未动,现在设置 M3600,那么 max-age=expires-r->request_time = -7200 实际上我们可以看到这样的例子:

5、将 expires 时间转换成 GMT 格式,生成 Expires 头,Expires 的值为 expires 时间的 GMT 格式。(arp_table_setn()函数)
当 Apache 返回 Response 后,我们可以看到同时设置了 Cache-Control 和 Expires 头:

注意:返回的头包括它们的值我们都可以在源代码里面修改(这里我已经修改),但是如果不如何 HTTP1.1 的标准也是没用的。

Appendix:关于 HTTP 1.1 Cache

1、当访问一个静态文件后,IE 会在本地缓存此文件,如果按 Enter,会看到(Cache),表示文件是本地缓存的;

2、如果按 F5(不是 Ctrl+F5),IE 重新发起请求到 Web Server,如果没有过期,Web Server 返回 304:
“GET /index.html HTTP/1.1” 304 - “-“

Apache 会有这种日志。说明 Apache 接受了请求, 但是除了发生头部外,没传送任何字节:
这里最后一个字段:%b => 以 CLF 格式显示的除 HTTP 头以外传送的字节数,也就是当没有字节传送时显示’-‘而不是 0

如果要减轻 backend Server 的压力,不要 Backed Server 接受到任何无用的请求(304), 那么在 Backend Server 前端设置 Squid Server,由 Squid 来返回 304. 而不到后端 Server 进行验证而带来大量 304 请求。
3、Ctrl+F5 则相当于一次新的请求。

本文地址 https://shaoshilei.com/2014-03/apache-module-configuration-wording-of-modexpires-reserved.html