代码之家  ›  专栏  ›  技术社区  ›  AlexV

在PHP中回答http_if_modified_since和http_if_none_匹配

  •  11
  • AlexV  · 技术社区  · 15 年前

    我有用php 5.1.0+制作的可缓存动态内容。我已经将正确的头(包括最后修改的和etag)发送给客户机。

    我现在希望我的脚本能够回答 $_SERVER['HTTP_IF_MODIFIED_SINCE'] $_SERVER['HTTP_IF_NONE_MATCH'] 在场时。当条件匹配时,我想回答 HTTP 304 "Not Modified" 致客户。

    正确的条件是什么?我什么时候发布的是304而不是整个内容?

    接受的问题答案 How to know when to send a 304 Not Modified response 似乎这个问题是正确的,但我很难将代码移植到PHP5。

    谢谢您!

    7 回复  |  直到 6 年前
        1
  •  31
  •   Community CDub    12 年前

    我一直使用:

    function caching_headers ($file, $timestamp) {
        $gmt_mtime = gmdate('r', $timestamp);
        header('ETag: "'.md5($timestamp.$file).'"');
        header('Last-Modified: '.$gmt_mtime);
        header('Cache-Control: public');
    
        if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
            if ($_SERVER['HTTP_IF_MODIFIED_SINCE'] == $gmt_mtime || str_replace('"', '', stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])) == md5($timestamp.$file)) {
                header('HTTP/1.1 304 Not Modified');
                exit();
            }
        }
    }
    

    不记得是我写的还是从别的地方得到的…

    我通常在文件的顶部这样使用它:

    caching_headers ($_SERVER['SCRIPT_FILENAME'], filemtime($_SERVER['SCRIPT_FILENAME']));
    
        2
  •  3
  •   Wim    15 年前

    你所引用的答案似乎包含了你所需要的一切。总结:

    • 生成您自己的etag和最后修改的头文件,就像发送整个正文一样。
    • 查看客户端发送的if-modified-since头,如果您自己的上次修改时间较旧,或者发送304
    • 查看客户端的if none匹配头,如果它与您自己的etag匹配,则发送304
    • 如果到达此位置,则邮件头不匹配,请发送完整的正文和新的etag/上次修改的邮件头
        3
  •  1
  •   Bob Fanger    15 年前

    这是我的render_file()函数的一个片段。

    $last_modified = filemtime($filename);
    if ($last_modified === false) {
      throw new Exception('Modify date unknown');
    }
    if (array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER)) {
      $if_modified_since = strtotime(preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE']));
      if ($if_modified_since >= $last_modified) { // Is the Cached version the most recent?
        header($_SERVER['SERVER_PROTOCOL'].' 304 Not Modified');
        exit();
      }
    }
    header('Last-Modified: '.date('r', $last_modified)); // tz should be GMT according to specs but also works with other tzs
    
    // other headers and contents go here  
    
        4
  •  1
  •   MitchellK    6 年前

    如果我能稍微改进一下Rich Bradshaw最初的精彩回答 https://stackoverflow.com/users/16511/rich-bradshaw

    此代码经过了调整,现在100%通过了if-modified-since和if-none匹配检查。它还正确设置了上次修改日期的格式,因为原始答案在末尾发送+0000而不是GMT,并将vary头添加到304响应中。你可以在redbot.org上测试这个。

    <?php
    function caching_headers ($file, $timestamp) {
        $lastModified=filemtime($_SERVER['SCRIPT_FILENAME']);
        $gmt_mtime = gmdate("D, d M Y H:i:s T", $lastModified);
        header('ETag: "'.md5($timestamp.$file).'"');
        header('Last-Modified: '.$gmt_mtime);
        header('Cache-Control: must-revalidate, proxy-revalidate, max-age=3600');
    
        if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
            if ($_SERVER['HTTP_IF_MODIFIED_SINCE'] == $gmt_mtime || str_replace('"', '', stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])) == md5($timestamp.$file)) {
                header('HTTP/1.1 304 Not Modified');
                header("Vary: Accept-Encoding,User-Agent");
                exit();
            }
        }
    }
    caching_headers ($_SERVER['SCRIPT_FILENAME'], filemtime($_SERVER['SCRIPT_FILENAME']));
    ?>
    
        5
  •  0
  •   mr-sk    15 年前

    如果客户执行了 条件获取请求和访问是 允许,但文档尚未 修改后,服务器应响应 使用此状态代码。304 响应不能包含 消息体,因此始终 以第一个空行结束 在标题字段之后。

    从- http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5

    所以,如果你寄304,不要寄尸体。

        6
  •  0
  •   John Magnolia Mozammil    13 年前

    This article 将回答关于缓存的所有问题

    我发现

    RewriteRule .* - [E=HTTP_IF_MODIFIED_SINCE:%{HTTP:If-Modified-Since}]
    RewriteRule .* - [E=HTTP_IF_NONE_MATCH:%{HTTP:If-None-Match}]
    

    在我的htaccess文件的底部(在所有rewriterule下面)工作正常。

        7
  •  -3
  •   symcbean    15 年前

    为什么?

    在对这个主题做了大量的研究之后,我发现有条件的请求实际上会减慢一个站点的运行速度。在某些情况下,情况并非如此,但总体上,映射到一般使用模式会导致较低的吞吐量和较低的缓存效率。

    C.