首先简单介绍下apache的expires模块,详细的apache expires介绍可以点这里:http://www.laoona.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://laoona.com/post/b8da62b7.html