说在开头 javascript
《高性能建站指南》看了不少遍,一直没有搞清楚缓存这一块。。什么expired,last-modified,eTag等等,本身只是知道,并无深刻了解,在http请求中,这些字段是如何判断是否须要从服务端从新拿文件仍是利用缓存。看到了一篇不错的文章,分享一下。 css
正文 html
每次访问网页,一般浏览器会从服务器下载所需的资源,例如 HTML 文档、图片、CSS、JavaScript,甚至包括字体文件等。这里面的许多文件(例如图片)都是不多变更的,若是每次都要从服务器从新下载,会没必要要地增长网页载入时间,同时也会对服务器形成必定压力。经过合理配置缓存策略,可令浏览器以某种方式把这些静态的文件缓存起来,下次请求同一资源时,直接使用本地存储的副本,而不是从服务器从新下载。
java
启用缓存至少有两点显而易见的好处:web
减小页面加载时间正则表达式
减小服务器负载apache
浏览器是否使用缓存、缓存多久,是由服务器控制的。准确来讲,当浏览器请求一个网页(或者其余资源)时,服务器发回的响应的「响应头」部分的某些字段指明了有关缓存的关键信息。浏览器
Cache-Control缓存
Cache-ControlHTTP 响应头是 HTTP 1.1 协议新增的指令,每一个资源均可以经过设定 Cache-Control 来创建缓存策略。一般,可为它指定一个max-age,表示缓存的最长时间,单位为秒。例如,若设定Cache-Control: max-age=604800,则表示这个资源的有效时间为 7 天。浏览器第一次获取这个资源后,7 天以内若再次请求,一般都不会与服务器进行任何通讯,而是直接使用本地副本。安全
此外,还能够为 Cache-Control 指定public或private标记。若是使用 private,则表示该资源仅仅属于发出请求的最终用户,这将禁止中间服务器(如代理服务器)缓存此类资源。对于包含用户我的信息的文件(如一个包含用户名的 HTML 文档),能够设置 private,一方面因为这些缓存对其余用户来讲没有任何意义,另外一方面用户可能不但愿相关文件储存在不受信任的服务器上。须要指出的是,private 并不会使得缓存更加安全,它一样会传给中间服务器(若是网站对于传输的安全性要求很高,应该使用传输层安全措施)。对于 public,则容许全部服务器缓存该资源。一般状况下,对于全部人均可以访问的资源(例如网站的 logo、图片、脚本等),Cache-Control 设为 public 是合理的。
Expires
一样是用来控制缓存,Expires响应头从另外一个角度——指明缓存的具体过时日期,来控制资源什么时候过时。在过时时间之内,若再次发起请求,一般浏览器都不会与服务器进行任何通讯,而是直接使用本地副本。Apache 服务器容许以多种方式,例如基于该资源的访问时间或上次修改时间来设定 Expires 的值。注意,这里的时间一概使用格林威治时间(Greenwich Mean Time, GMT),而非本地时间。
当 Expires 和 Cache-Control 同时出现时,一般后者会覆盖前者的设定。因为 Expires 对用户的系统时间有所依赖,所以一般认为使用 Cache-Control 是更好的选择(基本上全部的浏览器都支持 Cache-Control 指令)。
Last-Modified 和 ETag
服务器可在 HTTP 返回头中包含Last-Modified字段或者ETag字段。Last-Modified 表示被请求资源在服务器端的上次修改时间,而 ETag 则是一个惟一文件标识符,每次文件修改后都会生成一个新的 ETag。服务器经过向浏览器发送这两个字段,来告知浏览器其得到的资源的版本。
不管经过 Cache-Control 仍是 Expires 设置缓存,在过时时间之内,当用户点击浏览器刷新按钮时,为了确保用户所加载的资源是最新的,大部分浏览器不会再直接使用缓存中的数据,而是发出一个条件请求(Conditional GET Request)。对于这类请求,浏览器会在请求头中包含If-Modified-Since或If-None-Match字段。前者即浏览器当初获得的 Last-Modified;后者即浏览器当初获得的 ETag。当服务器发现资源的更新时间晚于 If-Modified-Since 所提供的时间,或者资源在服务器端当前的 ETag 和 If-None-Match 提供的不符时,会响应整个资源,不然只会响应一个 304 Not Modified 状态码(所以浏览器将不须要从新下载整个资源)。这种机制能够最大程度上减小数据下载量。此外,若是缓存的资源已过时,浏览器一般有两种选择:从新下载这个资源,或发出一个条件请求。不少浏览器都会采起后者,以节约资源。
因为 Last-Modified 和 ETag 的做用是相同的(均为向服务器验证资源是否最新),所以只使用一个便可。一般认为 Last-Modified 更好(它和 Expires 不一样,由服务器生成,不依赖浏览器端时间)。
个人网站启用缓存了吗?
用浏览器的开发者工具或插件查看
为了肯定是否启用了缓存,只须要检查服务器发回的「响应头」就能够。许多浏览器以及工具均可以检查这些信息,咱们以 Firefox 的插件 Firebug 为例。如图所示:
没有包含Cache-Control以及Expires信息。
在线检测
也有一些方便的在线检测服务,用于对网站速度给出建议,其中就会检测缓存设置状况。好比 Yahoo! 公司的 YSlow,以及百度站长工具等,都有相应的功能。你们能够去百度那里检测一下,目前是不须要登陆便可检测的。
使用缓存的策略
为静态资源设置长缓存时间
有些资源是很长时间不会改变的,好比网站的 logo 图片、jQuery 库、字体等,所以能够为它们设定「永不过时」的缓存时间,例如设定为 10 年。
确保文件修改生效
有些时候咱们会修改一些资源,好比更新了 jQuery 版本,或网站的 CSS 样式。若是这些资源已经被缓存,那么除非用户手工刷新页面,不然要等缓存天然过时以后用户才会得到新版本。如何在这种状况下强制浏览器从新下载呢?最有效的一个办法就是在这类资源的文件名中包含版本信息,并在更改以后对应地修改文件名。浏览器发现文件更换后,天然没法使用缓存,而会从新下载。
对于 HTML 文档谨慎设定过时时间
大部分状况下,对于其余图片、CSS、JavaScript 等资源的请求都来自一个单一的 HTML 文档。对于这类页面一般应该设定比较短的过时时间,或者干脆不设定。由于若是这类页面被缓存,那么页面中包含的资源的文件名等等信息都会一并被缓存,致使对它的更新难以确保当即对用户生效。
引用静态资源时,不要使用 Query String
Query String 就是例如?key=val的字符串,如
<script src="/static/js/func.js?v=a87ff8"></script>
这会阻止一部分较老的浏览器(包括 IE6 )对该资源进行缓存。
设定缓存的方法
对于 Apache 服务器,能够经过 mod_expires 模块来设定ExpiresHTTP 头或Cache-ControlHTTP 头的max-age指令。编辑相应目录下的 .htaccess 文件,或直接对 Apache 的配置文件(根据服务器系统版本不一样,可能为httpd.conf或apache2.conf等)做出修改。
分文件类别设定
使用ExpiresByType能够按照文件的 MIME Type 设定某一类文件的过时日期。例如:
<IfModule mod_expires.c> ExpiresActive On ExpiresByType text/css "access plus 1 week" ExpiresByType application/javascript "access plus 2 weeks" ExpiresByType p_w_picpath/x-icon "access plus 6 months" ExpiresByType p_w_picpath/gif "access plus 6 months" ExpiresByType p_w_picpath/png "access plus 6 months" ExpiresByType p_w_picpath/jpeg "access plus 6 months" ExpiresByType video/x-flv "access plus 6 months" ExpiresByType application/pdf "access plus 6 months" </IfModule>
其中access plus 1 week表示将缓存过时设置为访问时间(即当前时间)以后的一周。若是将access替换为modification,则缓存过时会被设定为文件修改时间以后的一周。可使用的时间单位包括:
years months weeks days hours minutes seconds
不一样的时间也能够进行组合,例如:
ExpiresByType text/html "access plus 1 month 15 days 2 hours" ExpiresByType p_w_picpath/gif "modification plus 5 hours 3 minutes"
根据文件扩展名进行设置
若是但愿根据扩展名来指定缓存规则,可使用FilesMatch配合正则表达式。为了简洁,我这里只规定了ExpiresDefault。它的优先级很低,只会在对应文件没有任何其余规则可以匹配(包括上层目录下的缓存规则)时生效。
<IfModule mod_expires.c> <FilesMatch "\.(css|js)$"> ExpiresActive on ExpiresDefault "access plus 1 week" </FilesMatch> </IfModule>
对某些文件设定
同理,也能够对某些文件启用特定的缓存策略。注意,文件名中的点(.)是须要转义的。
<IfModule mod_expires.c> <FilesMatch "^(example\.css|example\.js)$"> ExpiresActive on ExpiresDefault "access plus 1 week" </FilesMatch> </IfModule>
对某一文件夹下的全部文件设定
对于静态文件,一个比较方便的作法是将它们所有放到一个目录下,并对该目录下的全部文件设定。可是,此处须要注意防止其余规则将ExpiresDefault覆盖掉。
<IfModule mod_expires.c> ExpiresActive On ExpiresDefault "access plus 10 years" </IfModule>
有用的工具及参考资料
Cache-Control header checker(可检测给定的地址是否启用了 Cache-Control,还会教你如何设定)
Caching Tutorial for Web Authors and Webmasters