网站缓存技术之浏览器缓存

 前些日子搭建的网站对性能比较有要求,自己就到处寻找,研究优化方面的技术。发现缓存真是个好东西,用的好了,提升效果那是相当明显的。不过缓存技术真是多种多样,几乎网站的各个层次都有相应的缓存技术。网上的资料多但是太散,自己就在这做一个总结,欢迎大家扔板砖啊^_^

        在这一篇先介绍一下浏览器缓存,浏览器缓存的使用就是为了减少http请求,减少带宽流量。浏览器缓存所涉及到的知识有:”Last-Modified” , ”Etag” ,Expires , "Cache-Control:" 。
      
        基础知识:

       1) 什么是”Last-Modified”? 

         在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是你请求的资源,同时有一个Last-Modified的属性标记此文件在服务期端最后被修改的时间,格式类似这样: 

         Last-Modified: Fri, 12 May 2006 18:53:33 GMT 

         客户端第二次请求此URL时,根据 HTTP 协议的规定,浏览器会向服务器传送 If-Modified-Since 报头,询问该时间之后文件是否有被修改过: 

         If-Modified-Since: Fri, 12 May 2006 18:53:33 GMT 

         如果服务器端的资源没有变化,则自动返回 HTTP 304 (Not Changed.)状态码,内容为空,这样就节省了传输数据量。 当服务器端代码发生改变或者重启服务器时,则重新发出资源,返回和第一次请求时类似。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能 够得到最新的资源。 

         2) 什么是”Etag”? 

         HTTP 协议规格说明定义ETag为“被请求变量的实体值” (参见 —— 章节 14.19)。 另一种说法是,ETag是一个可以 与Web资源关联的记号(token)。典型的Web资源可以一个Web页,但也可能是JSON或XML文档。服务器单独负责判断记号是什么及其含义,并 在HTTP响应头中将其传送到客户端,以下是服务器端返回的格式: 

         ETag: "50b1c1d4f775c61:df3" 

         客户端的查询更新格式是这样的: 

         If-None-Match: W/"50b1c1d4f775c61:df3" 

         如果ETag没改变,则返回状态304然后不返回,这也和Last-Modified一样。本人测试Etag主要在断点下载时比较有用。
        
       Last-Modified和Etags如何帮助提高性能?
         聪明的开发者会把Last-Modified 和ETags请求的http报头一起使用,这样可利用客户端(例如浏览器)的缓存。因为服 务器首先产生 Last-Modified/Etag标记,服务器可在稍后使用它来判断页面是否已经被修改。本质上,客户端通过将该记号传回服务器要求服 务器验证其(客户端)缓存。 
         过程如下:
                 1. 客户端请求一个页面(A)。 
                 2. 服务器返回页面A,并在给A加上一个Last-Modified/ETag。 
                 3. 客户端展现该页面,并将页面连同Last-Modified/ETag一起缓存。 
                 4. 客户再次请求页面A,并将上次请求时服务器返回的Last-Modified/ETag一起传递给服务器。 
                 5. 服务器检查该Last-Modified或ETag,并判断出该页面自上次客户端请求之后还未被修改,直接返回响应304和一个空的响应体。
 

       (3)Expires?
           Add an Expires   header,给文件加上关于过期时间的header报文。这个文件过期时间,其实就是通过header报文来指定特定类型的文件在浏览器中的缓存时间。有些文件(例如样式表中调用的背景图片和文章中调用的图片)其实在很长一段时间内我们都不会对它们有什么改变,这类文件可以设置非常长的缓存时间,这样浏览器以后就不需要再从服务器下载这些文件而直接从缓存中读取,从而大大加速网站的载入速度。 
        (4)Cache-Control
          Cache-Control指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置Cache-Control并不会修改另一个消息处理过程中的缓存处理过程。请求时的缓存指令包括no-cache、no-store、max-age、max-stale、min-fresh、only-if-cached,响应消息中的指令包括public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。各个消息中的指令含义如下: Public指示响应可被任何缓存区缓存。 Private指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。 no-cache指示请求或响应消息不能缓存 no-store用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。 max-age指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。 min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。 max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。

           应用
       
Last-Modified/tag 搭配使用时,可以减少传输成本,但不会减少http请求,我测试的图如下: 根据Yslow的说法,最优的设置就是关闭关闭Etag标签。
     
      在apache中使用命令FileETag None即可


     图中可见虽然减少了传输,但依旧是20个http请求。


Add an Expires   header,给文件加上关于过期时间的header报文,这样浏览器就会先检查缓存中的文件,如果没有过期,就直接使用缓存中的文件.在apache中的设置如下:
   
  <IfModule mod_expires.c>  
   ExpiresActive On  
   ExpiresDefault A600  
   ExpiresByType image/x-icon A2592000  
   ExpiresByType application/x-javascript A604800  
   ExpiresByType text/css A604800  
   ExpiresByType image/gif A2592000  
   ExpiresByType image/png A2592000  
   ExpiresByType image/jpeg A2592000  
   ExpiresByType text/plain A86400  
   ExpiresByType application/x-shockwave-flash A2592000  
   ExpiresByType video/x-flv A2592000  
   ExpiresByType application/pdf A2592000  
   ExpiresByType text/html A600  
   </IfModule>


         text/css表示样式表文件,text/plain代表的纯文本类文件,依次类推。那个A2592000就表示这种类型文件在浏览器中的缓存时间,以 秒为单位。一天86400秒,2592000就表示这类文件可以缓存30天。如果你不是经常修改模板,那样式表文件和javasctipt文件基本上也可 以设置缓存一周到一个月左右。text/html文件不要设置太长的缓存时间,因为这些东西修改的频率很高,而且大部分blog的访客平均访问时间能到 10分钟的并不多。    

   再用Yslow测试如下:

   减少了传输,也减少了请求

在这里使用了apache的mod_expires模块,所以要加载这个模块:LoadModule expires_module modules/mod_expires.so

提示:Keep in mind, if you use a far future Expires header you have to change the component's filename whenever the component changes. At Yahoo! we often make this step part of the build process: a version number is embedded in the component's filename, for example, yahoo_2.0.6.js. 


如果你对元件设置了比较长时间的缓存,如果你更新了这个元件,你的改一下名字。

   php代码实现:

if (($src_uri = realpath( $_GET["uri"] )) === false) {
    /* The file does not exist */
    header( "HTTP/1.1 404 Not Found" );
    echo( "<html><body><h1>HTTP 404 - Not Found</h1></body></html>" );
    exit;
}
/*
* Set the HTTP response headers that will
* tell the client to cache the resource.
*/

$file_last_modified = filemtime( $src_uri );
header( "Last-Modified: " . date( "r", $file_last_modified ) );

$max_age = 300 * 24 * 60 * 60; // 300 days

$expires = $file_last_modified + $max_age;
header( "Expires: " . date( "r", $expires ) );

$etag = dechex( $file_last_modified );
header( "ETag: " . $etag );

$cache_control = "must-revalidate, proxy-revalidate, max-age=" . $max_age . ", s-maxage=" . $max_age;
header( "Cache-Control: " . $cache_control );

此代码我尚未测试,大家斟酌着用.


       说了这么多,其实大家在使用时,把Etag关闭,加上过期时间,然后用Yslow测测,看看效果.


参考资料:http://www.infoq.com/cn/articles/etags
                 http://www.lifetyper.com/archives/000087.html
                 http://developer.yahoo.com/performance/rules.html
                 http://www.websiteoptimization.com/speed/tweak/cache/

                  http://www.mnot.net/cache_docs/
冷锋
:hi.baidu.com/billdkj/modify/blog/ff0ead0003e55f17738b6579

原文地址:https://www.cnblogs.com/wangzong/p/2179636.html