【问题标题】:Caching image requests through PHP - If-Modified-Since not being sent通过 PHP 缓存图像请求 - If-Modified-Since 未发送
【发布时间】:2010-11-05 12:51:02
【问题描述】:

我正在通过 php 提供图像,并且在将其设置为响应 304 标头以节省加载时间时遇到了一些问题。

下面的大部分代码都是我在 php.net 上找到的。它可以工作,但总是以 200 响应。由于某种原因,即使我最初发送 Last-Modified 标头,任何请求都没有收到 If-Modified-Since 标头。这是在一个阿帕奇服务器。知道可能出了什么问题吗?

Example here.

此页面将从磁盘加载图像并将其显示到浏览器,同时发送 Last-Modified 标头。如果刷新页面,浏览器不会像它应该发送的那样发送 If-Modified-Since 标头。

define('SITEPATH', (dirname($_SERVER['SCRIPT_NAME']) == '/') ? '/' : dirname($_SERVER['SCRIPT_NAME']).'/');

$load_path = $_SERVER['DOCUMENT_ROOT'] . SITEPATH . 'fpo_image.jpg';

// Get headers sent by the client.
$headers    = apache_request_headers(); 
$file_time  = filemtime($load_path);

header('Cache-Control: must-revalidate');
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $file_time).' GMT');

if (isset($headers['If-Modified-Since']) && (strtotime($headers['If-Modified-Since']) == $file_time)) {

    header('HTTP/1.1 304 Not Modified');
    header('Connection: close');

} else {

    header('HTTP/1.1 200 OK');
    header('Content-Length: '. filesize($load_path));
    header('Content-type: image/jpeg');                         

    readfile($load_path);

}

【问题讨论】:

标签: php apache caching header


【解决方案1】:

ma​​ndor at mandor dot net posted a solution 在 PHP.net 文档中为我工作的标头函数:

<?php

        // Test image.
        $fn = '/test/foo.png';

        // Getting headers sent by the client.
        $headers = apache_request_headers();

        // Checking if the client is validating his cache and if it is current.
        if (isset($headers['If-Modified-Since']) && (strtotime($headers['If-Modified-Since']) == filemtime($fn))) {
            // Client's cache IS current, so we just respond '304 Not Modified'.
            header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($fn)).' GMT', true, 304);
        } else {
            // Image not cached or cache outdated, we respond '200 OK' and output the image.
            header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($fn)).' GMT', true, 200);
            header('Content-Length: '.filesize($fn));
            header('Content-Type: image/png');
            print file_get_contents($fn);
        }

    ?>

【讨论】:

    【解决方案2】:

    我认为应该是的

    if (isset($headers['If-Modified-Since']) && (strtotime($headers['If-Modified-Since']) >= $file_time)) {
    

    检查修改的时间是否大于或等于而不是仅仅等于。虽然我确实理解这两个值应该是相同的。

    【讨论】:

    • 知道为什么 php 没有为后续请求接收到“If-Modified-Since”吗?我正在调试 $headers 值,但它从未出现在那里。假设您所要做的就是设置一个“Last-Modified”,它应该会显示出来。
    • 您确定您的浏览器正在发送它吗?使用 LiveHTTPHeaders 之类的插件来验证这一点。另外,当我这样做时,我使用 $_SERVER[] 而不是 apache_request_headers()
    • 是的,我非常奇怪地检查了 _SERVER 和 apache_request_headers()。也许我应该举一个例子来展示。
    【解决方案3】:

    经过一段时间的搜索,我找到了答案。浏览器没有缓存任何东西(也没有发送If-Modified-Since),直到我发送了以下标头:

    Cache-Control: private;
    

    完成后一切正常。

    【讨论】:

      【解决方案4】:

      我必须使用 Keith 的解决方案,结合上面的 azkotoki 和 Zsolti 的帖子,以使一切按要求工作。

      所以,最后一个例子是:

      <?php
      
          // Test image.
          $fn = '/test/foo.png';
      
          session_cache_limiter(false);
          header('Cache-Control: private');
      
          // Getting headers sent by the client.
          $headers = apache_request_headers();
      
          // Checking if the client is validating his cache and if it is current.
          if (isset($headers['If-Modified-Since']) && (strtotime($headers['If-Modified-Since']) == filemtime($fn))) {
              // Client's cache IS current, so we just respond '304 Not Modified'.
              header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($fn)).' GMT', true, 304);
          } else {
              // Image not cached or cache outdated, we respond '200 OK' and output the image.
              header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($fn)).' GMT', true, 200);
              header('Content-Length: '.filesize($fn));
              header('Content-Type: image/png');
              print file_get_contents($fn);
          }
      
      ?>
      

      【讨论】:

      • 这对我有用,结合使用 $_SERVER["HTTP_IF_MODIFIED_SINCE"] 而不是 $headers
      【解决方案5】:

      检查该页面上是否正在使用会话,如果是,请尝试以下操作:

      session_cache_limiter(false);
      

      如果上述方法有效,以下是解释:

      php 的 session 机制发送一些自动缓存相关的 headers 以提高 session cookie 的隐私性,避免它被中间代理缓存:

      http://php.net/manual/en/function.session-cache-limiter.php

      这些自动标头导致浏览器永远不会发送 If-Modified-Since 标头,因为它们指示浏览器根本不执行任何缓存。

      【讨论】:

        猜你喜欢
        • 2018-01-27
        • 1970-01-01
        • 2019-02-07
        • 2012-04-19
        • 2010-09-06
        • 1970-01-01
        • 1970-01-01
        • 2010-12-27
        • 2016-02-25
        相关资源
        最近更新 更多