浏览器的缓存机制:

  • 1: 浏览器会在第一次请求完服务器后得到响应, 我们可以在服务器中设置这些相应,
    从而达到在以后的请求中尽量减少甚至不从服务器获取资源的目的。
  • 2: 浏览器缓存中涉及到的头信息
    浏览器的缓存是依靠请求和响应中的的头信息来控制缓存的。

    1: expires
    最简单的过期缓存方式, 在第一次请求时返回的头信息中设置一个exires时间,在后面的请求的时候, 请求会带着这个expires时间, 假如在这个expires时间内,浏览器不会向服务器发送请求, 而是直接从本地缓存副本中读取数据

    2:Cache-Control
    他有一些不同的值对应不同的缓存策略,这里我查到一个,参考一下初探 HTTP 1.1 Cache 機制
    这里要说明的是Cache-Control的设置会覆盖expires的设置, 而且常与Last-Modified和Etag配合使用

    3:Last-Modified/Last-Modified-Since
    在使用这个缓存策略的时候, 浏览器每次都会向服务器发送请求, 但服务器可以根据Last-Modified-Since向浏览器返回200或者304, 如果返回304, 就是告诉浏览器让它直接从客户端电脑的缓存中读取副本吧, 否则就会把请求的资源以200的方式返回给浏览器。

    这里也要说明一下, Last-Modified是浏览器第一次向服务器请求之后, 服务器响应中设置的(即代码中设定), 而Last-Modified-Since则是浏览器每次向服务器请求的时候带着的Last-Modified的值, 比如第一次请求后响应的Last-Modified的值是A, 那么在后面每次请求的时候的Last-Modified-Since的值就是A, 直到服务器重新设置了Last-Modified的值

    4: Etag/If-None-Match
    ETag是一种与Last-Modified/Last-Modified-Since类似的控制方式。用户在第一次请求的时候服务器可以自己生成或由用户生成, 然后响应给浏览器, 那么在以后的请求中,会带着If-None-Match, 它的值就是之前生成的Etag。 在服务器中对比服务器上的Etag与If-None-Match, 假如相同, 则返回304, 否则请求并返回服务器资源。

    这里有一个问题, 如何生成Etag, 尤其是动态页面中, 假如资源发生变化, Etag要重新生成。 我这里想到一种方式, 请求到服务器后, 还是要进行必要的代码运行, 在代码中, 拿到相关的变量生成一个Etag值, 对比传递上来的If-None-Match, 再判定返回的状态值。(原谅我的经验有限, 这只是一种方式,如果各位有新的思路, 欢迎加入讨论)。

    5: Cache-Control/Expires的优先级要高于Last-Modified/Etag,Cache-Control/Expires是控制浏览器是否向服务器拉资源, Last-Modified/Etag是服务器控制是否返回一个完整的请求资源,还是返回一个304, 假如本地连请求都不会拉, 那Last-Modified/Etag就无从谈起了.

实现:

下面使用PHP分别实现以上几种缓存方式, 一般服务器上的静态文件都会默认使用Last-Modified/Last-Modified-Since,
所以很多的静态文件在二,三,四。。。次刷新的时候都是304状态(Not Modified).

另外下面的过期时间都是格林威治时间才行,可以使用gmdate函数获取。
    /*
      Last-Modified/Last-Modified-Since
      我想这里如果用一些数据保存方式,如memcache或数据库, 把某个文件的修改时间保存起来, 如果文件修改了, 则更新这个数据, 然后每次刷新这里的这个页面的时候,先读取修改时间,  如果传递的$lastModifiedSince修改时间不符, 则重新读取, 否则返回304
      测试的结果是在在缓存时间内返回304
     */

     $cacheTime = 60;
     $lastModifiedSince = strtotime(@$_SERVER['HTTP_IF_MODIFIED_SINCE']);
     if($lastModifiedSince + $cacheTime > time())
     {
       header("HTTP/1.1 304"); 
       die('use cache');
     }
     header('Last-Modified: '.gmdate('D d M Y H:i:s', time()).' GMT');
     echo time();


/*
    Etag/If-None-Match
    测试的结果是在服务器上的资源未发生变化时返回的304
*/

    $user_id = 1;
    $etag = md5($user_id);


    $matchEtag = @$_SERVER['HTTP_IF_NONE_MATCH'];

    if($matchEtag == $etag)
    {
        header("HTTP/1.1 304");
        die('use cache');
    }

    header('Etag: '.$etag);
    echo time();

问题:

在测试expires和Cache-Control的max-age的时候, 本地缓存无效, 每次还是发起请求, 并没有读取缓存, 不知为何?
请看连接

PS: 文章中可能有错误的地方, 如果发现, 请及时指出


Yi_Zhi_Yu
1.9k 声望69 粉丝

PHPer,Sphinxer,Giter,Sheller,Pythoner


引用和评论

0 条评论