通过 PHP 缓存图像请求 - If-Modified-Since 未发送

Posted

技术标签:

【中文标题】通过 PHP 缓存图像请求 - If-Modified-Since 未发送【英文标题】:Caching image requests through PHP - If-Modified-Since not being sent 【发布时间】: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);


【问题讨论】:

+1 提问! If-Modified since 标头返回完整内容而不是 304 的一个非常相似的问题:***.com/questions/4810806/… 【参考方案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 标头,因为它们指示浏览器根本不执行任何缓存。

【讨论】:

以上是关于通过 PHP 缓存图像请求 - If-Modified-Since 未发送的主要内容,如果未能解决你的问题,请参考以下文章

使用 PHP 缓存生成的图像

在 PHP 中缓存动态图像

PHP7 opcache缓存清理问题

PHP7 opcache缓存清理问题

PHP7 opcache缓存清理问题

node.js - 将图像缓存到文件系统并将图像通过管道传输到响应