【问题标题】:How can I manage browser cache in PHP?如何在 PHP 中管理浏览器缓存?
【发布时间】:2015-09-04 17:43:50
【问题描述】:

我的想法很简单,获取所有 css 文件并在某个 css 文件更改时生成一个缩小的文件。然后告诉浏览器清除缓存。如果浏览器缓存中有未更改的文件,则使用它 - 因此用户无需每次都重新下载。

我正在使用以下代码片段来执行此操作。但是使用缓存的部分有点问题,大部分时间它都可以工作,但有时它告诉浏览器使用缓存版本(因为没有变化)并且浏览器正在使用旧版本并且用户必须进行客户端缓存刷新。

您能否给我一些建议如何做到这一点,以便每次发生更改时都会刷新客户端浏览器缓存,如果没有更改就使用缓存?

$cssFiles = getCssFiles();

$fm = new FileMinifier(FileMinifier::TYPE_CSS);
$lastModified = $fm->lastModification($cssFiles);
$savedLastModified = DateUtils::convertToTimestamp($this->system->systemSettings['cssLastChange']);

$etagFile = md5('css-file');
header("Content-type: text/css");
header("Pragma: public");
header('Cache-Control: public');
header("Last-Modified: " . gmdate("D, d M Y H:i:s", $lastModified) . " GMT");
header("Etag: $etagFile");

// if there is a change - generate new minified css
if ($lastModified > $savedLastModified)
{
    // take files minify them, save it and redirect to output, update last change time
    ...
}
// or use already generated
else
{
    $ifModifiedSince = (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : 0);
    $etagHeader = (isset($_SERVER['HTTP_IF_NONE_MATCH']) ? trim($_SERVER['HTTP_IF_NONE_MATCH']) : false);
    // if it is in chache use it! - no need for redownloading
    if (strtotime($ifModifiedSince) == $lastModified || $etagHeader == $etagFile)
    {
        header("HTTP/1.1 304 Not Modified");
        exit;
    }
    $this->data['text'] = file_get_contents(SystemInfo::getServerRoot() . '/public/css/minified.css');
}

【问题讨论】:

  • 99% 的时间浏览器自己都可以很好地工作,你想在这里解决什么问题?
  • 我有另一个经验,如果我想更新一些 css 文件,很多人没有看到 chagnes。所以我开始做类似 ...css?v=2 之类的事情,这会强制浏览器重新缓存它,但我想自动化这个过程,所以我尝试了上面的解决方案。
  • 你也许可以使用标题。需要重新验证或无缓存。
  • 问题是我认为在 HTTP_IF_MODIFIED_SINCE 标头中可能提供了错误的信息,因为它表示没有更改,因此标头未修改被发送,因此浏览器将使用缓存。我需要一些条件,因为浏览器每次都会以其他方式重新下载它。我在缓存方面没有太多经验,我尝试了很多解决方案,我认为这个是最好的。但也许我做错了,所以我希望有人能给我一些建议或学习链接。

标签: php css caching browser-cache


【解决方案1】:

您尝试做的事情令人钦佩,但这有点重新发明轮子。就 CSS 文件、JavaScript 文件等而言,现代浏览器在从缓存中提取未更改的文件方面已经做得很好了。

操作 HTTP 标头以通知浏览器文件更改是可行的,但在如何解释标头方面存在浏览器差异(尤其是旧版浏览器),这使得该方法充满了细微差别。

通过版本化您的 CSS 包含更容易实现您的目标。文件版本的变化会提示浏览器重新下载文件。

示例:

文件更改前:

<link href="http://yourwebsite.com/file.css?_=1.0.0.1" rel="stylesheet" type="text/css">

文件更改后:

<link href="http://yourwebsite.com/file.css?_=1.0.0.2" rel="stylesheet" type="text/css">

所有浏览器都会将 URI 参数的变化解释为一个新文件并重新下载。

还可以自动化版本控制,这样您就无需在每次更改后手动编辑包含行。这是一种方法...

示例:

<?php
    $ver = filemtime($filename);
    echo '<link href="http://yourwebsite.com/file.css?_='.$ver.'" rel="stylesheet" type="text/css">';
?>

该代码会将文件的修改日期(Unix 时间戳格式)附加到文件包含的 URI。

【讨论】:

  • 好的,我会改变机制,所以脚本只会生成缩小文件,但不会将其重定向到输出。我将使用 ` 这比告诉浏览器要容易得多去做。我之前使用过版本控制,但我没有得到这个想法。感谢您的启发!
  • 特别赞成通过时间戳进行自动版本控制。很棒的技术!
猜你喜欢
  • 2017-12-10
  • 2016-05-13
  • 2017-03-15
  • 2010-11-05
  • 1970-01-01
  • 1970-01-01
  • 2012-07-15
  • 2011-09-14
  • 2018-08-22
相关资源
最近更新 更多