通过 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】:mandor 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 未发送的主要内容,如果未能解决你的问题,请参考以下文章