Apache 中配置 expires
Expires、Cache-Control、Last-Modified、ETag是RFC 2616(HTTP/1.1)协议中和网页缓存相关的几个字段。前两个用来控制缓存的失效日期,后两个用来验证网页的有效性。要注意的是, HTTP/1.0有一个功能比较弱的缓存控制机制:Pragma,使用HTTP/1.0的缓存将忽略Expires和Cache-Control头。我们这里以Apache2.0服务器为例,只讨论HTTP/1.1协议。
首先,我们查看 php 动态网页,没有 expires 过期时间的响应头信息
php 动态网页是无法设置过期时间的,因为是动态的,其过期时间默认为 Expires: Wed, 11 Jan 1984 05:00:00 GMT
接着,我们查看 css 静态文件,设置了 expires 过期时间的响应头信息
css 静态文件可以设置过期时间, Expires 和 Cache-Control 中的 max-age 是对应的,其计算起始时间为 Date
这里,还需要注意两个字段:Last-Modified、ETag,以及返回的状态码 Status Code: 200 OK (from disk cache)
最后,给出一个Gzip压缩后,又设置了缓存日期的加载请求,效果非常明显、直观
如上图,gzip 是开启了网页压缩,详见米扑博客:Apache 启用 GZIP 压缩网页传输方法
Expires 是开启了过期时间,大量的 js、css 直接从本地浏览器缓存读取,减轻了服务器压力,大大提供了访问速度
好了,有了初步认识,下面开始正文啦
Expires
Expires字段声明了一个网页或URL地址不再被浏览器缓存的时间,一旦超过了这个时间,浏览器都应该联系原始服务器。
RFC告诉我们:“由于推断的失效时间也许会降低语义透明度,应该被谨慎使用,同时我们鼓励原始服务器尽可能提供确切的失效时间。”
对于一般的纯静态页面,如html、gif、jpg、css、js,默认安装的Apache服务器,不会在响应头添加Expires这个过期时间字段。Firefox浏览器接受到相应后,如果发现没有Expires字段,浏览器根据文件的类型和“Last-Modified”字段来推断出一个合适的失效时间,并存储在客户端。推测出的时间一般是接受到响应时间后的三天左右。
Apache的 expires_module 模块可以在Http响应头部自动加上Expires字段,在Apache的httpd.conf文件中进行如下配置:
#启用expires_module模块
LoadModule expires_module modules/mod_expires.so
# 启用有效期控制
ExpiresActive On
# GIF有效期为1个月
ExpiresByType image/gif A2592000
# HTML文档的有效期是最后修改时刻后的一星期
ExpiresByType text/html M604800
#以下的含义类似
ExpiresByType text/css “now plus 2 month”
ExpiresByType text/js “now plus 2 day”
ExpiresByType image/jpeg “access plus 2 month”
ExpiresByType image/bmp “access plus 2 month”
ExpiresByType image/x-icon “access plus 2 month”
ExpiresByType image/png “access plus 2 month”
注意:
对于 jsp、php等动态页面,如果在页面内部没有通过函数强制加上Expires,例如 header(”Expires: ” . gmdate(”D, d M Y H:i:s”) . ” GMT”),Apache服务器会把Wed, 11 Jan 1984 05:00:00 GMT 作为Expires字段内容,返回给浏览器,即认为动态页面总是失效的,而浏览器仍然会保存已经失效的动态页面。这也是本文开头介绍的 php 动态页面没有过期时间。
可以发现Firefox浏览器总是缓存所有页面,不管失效、不失效还是没有声明失效时间。即使缓存中声明了一个网页的实效日期是1970-01- 01 08:00:00,浏览器仍然会发送该文件在缓存中的Last-Modified和ETag字段。 如果在服务器端验证通过,返回304状态,浏览器就还会使用此缓存。
米扑博客推荐配置参数:
在 httpd.conf 文件末尾,手动添加如下内容:
vim conf/httpd.conf
FileETag None <IfModule mod_expires.c> ExpiresActive On ExpiresDefault "accesss plus 600 seconds" ExpiresByType text/html "accesss plus 600 seconds" ExpiresByType text/css "now plus 1 month" ExpiresByType text/min.css "now plus 1 month" ExpiresByType text/x-component "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/gif "access plus 1 month" ExpiresByType image/png "access plus 1 month" ExpiresByType image/bmp "access plus 1 month" ExpiresByType image/x-icon "access plus 3 months" ExpiresByType image/svg+xml "access plus 3 months" ExpiresByType audio/ogg "access plus 1 month" ExpiresByType video/mp4 "access plus 1 month" ExpiresByType video/ogg "access plus 1 month" ExpiresByType video/webm "access plus 1 month" ExpiresByType video/x-flv "access plus 1 month" ExpiresByType application/json "accesss plus 600 seconds" ExpiresByType application/xml "accesss plus 600 seconds" ExpiresByType application/pdf "access plus 1 month" ExpiresByType application/javascript "now plus 30 days" ExpiresByType application/x-javascript "now plus 30 days" ExpiresByType application/x-font-ttf "access plus 1 month" ExpiresByType application/font-woff "access plus 1 month" ExpiresByType application/font-woff2 "access plus 1 month" ExpiresByType application/x-shockwave-flash "access plus 1 month" </IfModule>
Cache-Control
Cache-Control字段中可以声明多些元素,例如no-cache, must-revalidate, max-age=0等。这些元素用来指明页面被缓存最大时限,如何被缓存的,如何被转换到另一个不同的媒介,以及如何被存放在持久媒介中的。但是任何一个 Cache-Control指令都不能保证隐私性或者数据的安全性。“private”和“no-store”指令可以为隐私性和安全性方面提供一些帮助,但是他们并不能用于替代身份验证和加密。
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值就是一致的。
如果失效日期Cache-Control : max-ag=0或者是负值,浏览器会在对应的缓存中把Expires设置为1970-01-01 08:00:00。
Last-Modified
Last-Modified和ETag是条件请求(Conditional Request)相关的两个字段。如果一个缓存收到了针对一个页面的请求,它发送一个验证请求询问服务器页面是否已经更改,在HTTP头里面带上 ETag 和 If Modify Since 头。服务器根据这些信息判断是否有更新信息,如果没有,就返回HTTP 304(Not Modify);如果有更新,返回HTTP 200和更新的页面内容,并且携带新的 ETag 和 Last-Modified
使用这个机制,能够避免重复发送文件给浏览器,不过仍然会产生一个HTTP请求。
一般纯静态页面本身都会有Last-Modified信息,Apache服务器会读取页面文件中的Last-Modified信息,并添加到http响应头部。
对于动态页面,如果在页面内部没有通过函数强制加上Last-Modified,例如header(”Last-Modified: ” . gmdate(”D, d M Y H:i:s”) . ” GMT”),Apache服务器会把当前时间作为Last-Modified,返回给浏览器。
无论是纯静态页面还是动态页面,Firefox浏览器巧妙地按照接受到服务器响应的时间设置缓存页面的Last-Modified,而不是按照http响应头部中的Last-Modified字段。
ETag
既然有了Last-Modified,为什么还要用ETag字段呢?因为如果在一秒钟之内对一个文件进行两次更改,Last-Modified就会不正确。因此,HTTP/1.1利用Entity Tag头提供了更加严格的验证。
Apache服务器默认情况下,会对所有的静态、动态文件的响应头添加ETag字段。
在Apache的httpd.conf文件中可以通过FileETag指令配置该选项。FileETag指令配置了当文档是基于一个文件时用以创建 Etag(entity tag)响应头的文件的属性。在Apache 1.3.22及以前,ETag的值是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。 如果一个目录的配置包含了‘FileETag INode MTime Size’而其一个子目录包含了‘FileETag -INode’那么这个子目录的设置(并会被其下任何没有进行覆盖的子目录继承)将等价于‘FileETag MTime Size’。
例如,本文开头 Expires 图2中,设置‘FileETag MTime Size’后,得到的 ETag: "426e-57377c80fbf1a-gzip"
在多台负载平衡的服务器环境下,同一个文件会有不同的etag或者文件修改日期,浏览器每次都会重新下载。设置‘FileETag None’可以使响应头不再包含ETag字段。
设置‘FileETag None’后,得到的 ETag 字段将会隐藏消失,不再显示出来
Apache提供了mod_expires.so模块,可以轻松的设置expires值,以下是配置的范例:
LoadModule expires_module modules/mod_expires.so
ExpiresActive On
ExpiresDefault "access plus 300 seconds" # 默认300秒过期
<Directory "/var/www/html"> #文件所在目录
Options FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
Allow from all
ExpiresByType text/html "access plus 1 day" #设置cache时间为1天
ExpiresByType text/css "access plus 1 day"
ExpiresByType text/javascript "access plus 1 day"
ExpiresByType image/gif "access plus 1 day"
ExpiresByType image/jpg "access plus 1 day"
ExpiresByType image/png "access plus 1 day"
ExpiresByType application/x-shockwave-flash "access plus 1 day"
</Directory>
对于同一个操作对象,ExpiresByType比ExpiresDefault优先级高,当expires和max-age同时存在时,max-age的优先级会高于expires.
当你不知道某个文件的MIME类型时,你可以通过浏览器去看httpwatch去看MIME类型.
如果要对某个目录里的某个文件设置Expires头,可以用<filesmatch "正则"></filematch>来匹配.
设置缓存也可以通过mod_headers模块修改cache-control来实现.
header set cache-control "max-age="3600".
mod_expires 实例:
<Directory /opt>
ExpiresActive On
ExpiresDefault "accesss plus 3600 seconds" 如果是1秒,后面也是seconds
ExpiresByType application/octet-stream "accesss plus 1 months" 这是对特殊文件类型bin缓存1个月
<FilesMatch ^data.swf$> 针对opt目录下data.swf设置Expire值
ExpiresActive On
ExpiresDefault "accesss plus 60 seconds"
</FilesMatch>
</Directory>
mod_headers实例:
<Directory /opt>
header set cache-control "max-age=3600"
<FilesMatch ^data.swf$>
header set cache-control "max-age=60"
</FilesMatch>
</Directory>
Apache开启deflate(Gzip)和Expires提升网页加载速度
在Apache的配置文件中找到下面行,将注释#去掉,重启。
LoadModule deflate_module modules/mod_deflate.so
LoadModule expires_module modules/mod_expires.so
LoadModule header_module modules/mod_header.so
在http.conf后面加上这一段进行定制:(如非必要,用默认的就好了)
<ifmodule mod_deflate.c> AddOutputFilterByType DEFLATE text/html text/plain text/css application/x-httpd-php text/javascript application/x-javascript text/css AddOutputFilter DEFLATE js css #压缩js,css文件 # Don't compress images #对照片文件不进行压缩处理 SetEnvIfNoCase Request_URI (?:gif|jpe?g|png)$ no-gzip dont-vary SetEnvIfNoCase Request_URI (?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary SetEnvIfNoCase Request_URI .pdf$ no-gzip dont-vary #SetEnvIfNoCase Request_URI .(css|js)$ no-gzip dont-vary # Make sure proxies don't deliver the wrong content Header append Vary User-Agent env=!dont-vary DeflateCompressionLevel 6 SetOutputFilter DEFLATE </ifmodule> <IfModule mod_expires.c> ExpiresActive On ExpiresByType text/css "now plus 1 month" ExpiresByType application/x-javascript "now plus 5 day" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/gif "access plus 1 month" ExpiresByType image/bmp "access plus 1 month" ExpiresByType image/x-icon "access plus 1 month" ExpiresByType image/png "access plus 1 month" ExpiresByType application/x-shockwave-flash "access plus 1 month" </IfModule>
#使用mod_headers #在.htaccess文件中添加如下内容可以实现缓存: <ifmodule mod_headers.c> # htm,html,txt类的文件缓存一个小时 <filesmatch "/.(html|htm|txt)$"> header set cache-control "max-age=3600" </filesmatch> # css, js, swf类的文件缓存一个星期 <filesmatch "/.(css|js|swf)$"> header set cache-control "max-age=604800" </filesmatch> # jpg,gif,jpeg,png,ico,flv,pdf等文件缓存一年 <filesmatch "/.(ico|gif|jpg|jpeg|png|flv|pdf)$"> header set cache-control "max-age=29030400" </filesmatch> </ifmodule>
这样可以压缩一般网页中会用到的html、xml、php、css、js等格式档案输出,虽然会占用掉服务器处理器的一点点处理器时间,浏览者在接收网页数据时也会消耗极短暂的一点点处理器时间,不过却可以大幅减少数据传输量,减少网络带宽被吃掉的情形。
DeflateCompressionLevel 9是指压缩程度的等级,从1到9,9是最高等级。据了解,这样做最高可以减少8成大小的传输量(看档案内容而定),最少也能够节省一半。
DeflateCompressionLevel 预设可以采用 6 这个数值,以维持耗用CPU处理器效能与网页压缩质量的平衡。
Apache 手册 节选,或查看 Apache 官网文档:Apache 2.4 Module mod_expires
ExpiresDefault
和ExpiresByType
指令同样能够用易懂的语法格式进行定义:
ExpiresDefault "<base> [plus] {<num> <type>}*"
ExpiresByType type/encoding "<base> [plus] {<num> <type>}*"
其中<base>是下列之一:
-
access
-
now
(等价于'access
') -
modification
plus
关键字是可选的。<num>必须是整数[可以被atoi()
接受的],<type>是下列之一:
-
years
-
months
-
weeks
-
days
-
hours
-
minutes
-
seconds
例如,下列3个指令都表示文档默认的有效期是一个月:
ExpiresDefault "access plus 1 month"
ExpiresDefault "access plus 4 weeks"
ExpiresDefault "access plus 30 days"
有效期可以通过增加"<num> <type>"子句进一步调整:
ExpiresByType text/html "access plus 1 month 15 days 2 hours"
ExpiresByType image/gif "modification plus 5 hours 3 minutes"
注意,如果你使用基于最后修改日期的设置,"Expires:"头将不会 被添加到那些并非来自于磁盘文件的内容。这是因为这些内容并不存在"最后修改时间"的属性。
HTTP头的Expires与Cache-control
1. 概念
Cache-control用于控制HTTP缓存(在HTTP/1.0中可能部分没实现,仅仅实现了Pragma: no-cache)
数据包中的格式:
Cache-Control: cache-directive
cache-directive可以为以下:
request时用到:
| "no-cache"
| "no-store"
| "max-age" "=" delta-seconds
| "max-stale" [ "=" delta-seconds ]
| "min-fresh" "=" delta-seconds
| "no-transform"
| "only-if-cached"
| "cache-extension"
response时用到:
| "public"
| "private" [ "=" < "> field-name < "> ]
| "no-cache" [ "=" < "> field-name < "> ]
| "no-store"
| "no-transform"
| "must-revalidate"
| "proxy-revalidate"
| "max-age" "=" delta-seconds
| "s-maxage" "=" delta-seconds
| "cache-extension"
部分说明:
根据是否可缓存分为
Public 指示响应可被任何缓存区缓存。
Private 指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的
部分响应消息,此响应消息对于其他用户的请求无效。
no-cache 指示请求或响应消息不能缓存(HTTP/1.0用Pragma的no-cache替换)
根据什么能被缓存
no-store 用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。
根据缓存超时
max-age 指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
min-fresh 指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
max-stale 指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以
接收超出超时期指定值之内的响应消息。
Expires 表示存在时间,允许客户端在这个时间之前不去检查(发请求),等同max-age的
效果。但是如果同时存在,则被Cache-Control的max-age覆盖。
格式:
Expires = "Expires" ":" HTTP-date
例如
Expires: Thu, 01 Dec 1994 16:00:00 GMT (必须是GMT格式)
2. 应用
通过HTTP的META设置expires和cache-control
<meta http-equiv="Cache-Control" content="max-age=7200" />
<meta http-equiv="Expires" content="Mon, 20 Jul 2009 23:00:00 GMT" />
上述设置仅为举例,实际使用其一即可。这样写的话仅对该网页有效,对网页中的图片或其他请求无效,并不会做任何cache。
这样客户端的请求就多了,尽管只是检查Last-modified状态的东西,但是请求一多对浏览速度必定有影响。
如果要对文件添加cache可以通过apache的mod_expire模块,写法为
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 1 days"
</IfModule>
记得ExpiresActive设为On,我起先没设置On,似乎怎样YSlow都查不到缓存机制。这样添加的话就是默认所有的。
如果要针对个别MIME类型则可以:
ExpiresByType image/gif "access plus 5 hours 3 minutes"
见 Apache Module mod_expires
另外,当点击浏览器上的刷新,客户端发送的请求中均是max-age=0,表示validate操作,发送请求到服务器
要求检查cache,再更新cache,一般得到的是304 Not Modified,表示没变动。
参考文档:
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2018-08-20 22:11:29
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!