如何防止PHP站点的浏览器缓存


120

我有一个运行在云服务器中的php站点。每当我添加新文件css,js或图像时,浏览器就会加载存储在缓存中的旧js,css和图像文件。

我的网站具有doctype和meta标签,如下所示

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
  <meta http-equiv="Page-Enter" content="blendTrans(Duration=1.0)">
  <meta http-equiv="Page-Exit" content="blendTrans(Duration=1.0)">
  <meta http-equiv="Site-Enter" content="blendTrans(Duration=1.0)">
  <meta http-equiv="Site-Exit" content="blendTrans(Duration=1.0)">

由于上述doctype和元代码,我加载了浏览器中缓存的相同文件,而不是新文件


No Cache in all Browsers。您也可以对不想缓存的文件执行?randomGeneratedNumber。
科德蒙

2
你可能不希望禁用缓存完全用于图像/ JS / CSS:stackoverflow.com/questions/4206224/...
FoolishSeth

抵制了死灵的诱惑,但是请考虑的任何人:停止。学会控制和使用缓存,不要因为一个不方便的事件而盲目地禁用它。阅读有关从HTTP进行缓存的一章权威指南 -本书(和RFC)应该是必读的,并带有测试。了解如何指定“ Last-Modified”,如何响应“ If-Modified-Since”以及如何利用ETag标识。然后,当资产更新时,当304再次变为200时,将通知浏览器。
amcgregor

Answers:


282

试试这个

<?php

header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
?>

6
除了“ max-age = 0”以外,这些是PHP在我的安装中未指定上述标头的情况下发送的标头。似乎PHP默认尝试阻止浏览器缓存...
快速反射[

1
我有一个WordPress插件,可以将替代主题发送到旧版本的Internet Explorer,并且在某些缓存系统上被严重绊倒。这篇文章来自我的第一个Google搜索。打的好。
势在必行的2014年

3
请记住,这不能嵌入html内;这应该在页面的顶部。
猎人S

9
注意:如果您session_start()以后使用它,它将覆盖您的标头,Cache-Control: private, max-age=10800, pre-check=10800因为180分钟是默认值session.cache_expire。如果您无法避免启动会话,但是需要禁用缓存使用session_cache_limiter('private');session_cache_expire(0);
mgutt

2
@thdoan的第二个参数header函数是一个布尔用于替换。可选的replace参数指示标头是应替换先前的相似标头,还是添加第二个相同类型的标头。
mrReiha '19

36

在这里,如果您想通过HTML进行控制,请按照以下方法进行操作

<meta http-equiv="expires" content="Sun, 01 Jan 2014 00:00:00 GMT"/>
<meta http-equiv="pragma" content="no-cache" />

如果要通过PHP控制它,请按照以下方法2进行操作:

header('Expires: Sun, 01 Jan 2014 00:00:00 GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', FALSE);
header('Pragma: no-cache');

选项2总是更好,以避免基于代理的缓存问题。


10

您可以尝试以下方法:

    header("Expires: Tue, 03 Jul 2001 06:00:00 GMT");
    header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
    header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
    header("Cache-Control: post-check=0, pre-check=0", false);
    header("Pragma: no-cache");
    header("Connection: close");

希望它将有助于防止缓存(如果有)!


这仅与HTML文件的缓存有关吗?与eTag无关吗?谢谢!
莱文

4
仅第一行就足够了。第五行实际上是完全错误的,与服务器响应无关(它是一个请求标头)。第六行将不会产生任何影响。我可以继续...
Surrican

弹枪的方法:将所有东西扔在墙上,希望有东西粘住。根据我对问题本身的评论,我强烈建议您获取一份HTTP:The Definitive Guide副本,并阅读有关缓存的章节。也是RFC,但是阅读这些是一项独特的技能。(“连接:关闭”是一个有趣的选择,包括禁用请求的有效流水线操作,或者什么都不做,但是我怀疑PHP可能实际上允许它通过。)
amcgregor

7

我在缓存CSS文件时遇到问题。在PHP中设置标头并没有帮助我(也许是因为需要在样式表文件中设置标头,而不是页面链接到它吗?)。

我在此页面上找到了解决方案:https : //css-tricks.com/can-we-prevent-css-caching/

解决方案:

将时间戳记作为链接文件的URI的查询部分。
(可用于CSS,JS,图像等)

开发:

<link rel="stylesheet" href="style.css?<?php echo date('Y-m-d_H:i:s'); ?>">

对于生产(在大多数情况下,缓存是一件好事):

<link rel="stylesheet" type="text/css" href="style.css?version=3.2">
(并在需要时手动重写)

或这两个的组合:

<?php
    define( "DEBUGGING", true ); // or false in production enviroment
?>
<!-- ... -->
<link rel="stylesheet" type="text/css" href="style.css?version=3.2<?php echo (DEBUGGING) ? date('_Y-m-d_H:i:s') : ""; ?>">

编辑:

或这两个的更漂亮的组合:

<?php
    // Init
    define( "DEBUGGING", true ); // or false in production enviroment
    // Functions
    function get_cache_prevent_string( $always = false ) {
        return (DEBUGGING || $always) ? date('_Y-m-d_H:i:s') : "";
    }
?>
<!-- ... -->
<link rel="stylesheet" type="text/css" href="style.css?version=3.2<?php echo get_cache_prevent_string(); ?>">

任意版本,当前时间戳(完全击败缓存)……但无论是否有“调试”标志,这都不是真正有意义和可行的事情。为什么不使用文件的实际mtime?然后,您几乎不需要更新PHP,并且缓存也不会变得完全无用。或仅通过适当配置的HTTP服务器(例如Nginx或Apache)来提供您的静态信息,该服务器会设置适当的Last-Modified和ETag。同样,浏览器中已经存在这种类型的“调试”标志。(禁用缓存,不使用缓存刷新,清空缓存等)
amcgregor

5

视情况而定,防止浏览器缓存不是一个好主意。在寻找解决方案时,我发现了这样的解决方案:

<link rel="stylesheet" type="text/css" href="meu.css?v=<?=filemtime($file);?>">

这里的问题是,如果在服务器上的更新过程中文件被覆盖(这就是我的情况),则缓存会被忽略,因为即使文件内容相同,时间戳也会被修改。

我使用此解决方案来强制浏览器仅在修改其内容后才下载资产:

<link rel="stylesheet" type="text/css" href="meu.css?v=<?=hash_file('md5', $file);?>">

kes!这对于始终在主线程中加载所有CSS / JS文件以检查其大小/哈希值的性能和可伸缩性来说将是可怕的。
大林

@Dalin在您哭泣Gentoo Ricer的眼泪之前(我是一个Linux发行版,由于从源代码过度编译和架构调整而闻名,它“快速发展”),我会打个stat电话。没有文件系统缓存,16ns,顶部?具有高速缓存,可靠地<8ns。纳秒。在我的系统上,MD5可以处理754 MiB / s,而不会闪烁。(openssl speed md5)合并后,一个100KB的CSS文件的合并额外开销为……129µs(微秒,0.1295ms)+ 8ns(对最终数量没有意义)= 129µs。
amcgregor

经过进一步的考虑,我感到震惊的是,唯一的“正确”答案(维护负担最低,最准确/最可靠的行为)是投票最少的,并且在这种脆弱且不切实际的理由中仅发表了评论。
amcgregor

您和我可能在不同的网站上工作。但我支持我的评论。如果在任何时间点都有数十个并发线程在交付网页,那么我认为有更好的选择,您甚至不需要怀疑它是否可扩展。 hash_file('md5', $deployment_counter)还是hash_file('md5', $cache_clear_counter)第一个想到的。
大林
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.