我正在围绕一个较新的范例重写一堆表单,试图简化用于防止在用户使用“后退”按钮时重新处理过时表单数据的机制。我已经将它提炼成一个在 FF21、ie10(!)、Opera12.15 中工作的最小测试用例,但在 Chrome 27.0 和 Safari 5.1.7 上只是马马虎虎——而不是我预期会出现问题的浏览器,所以这可能是我自己的错。
表单 view.php 总是发布到 post.php,它完成所有工作,然后重定向到 view.php。(其中一些是设计页面,一些用户在其中迭代了很多次。)我的目标是避免“浏览器必须重新提交数据”消息,防止浏览器使用缓存视图,并防止 view.php 留下很长时间历史上的足迹。(一些消息来源称 PRG 阻止了这一点。)所有三个目标都在 FF、Opera 和 IE 中实现,在这些地方没有历史增长。Chrome 和 Safari 会在历史记录中显示相同页面浏览量的踪迹。查看请求/响应标头,Chrome 似乎对任何重新访问的历史页面进行了完整的 GET,但它显示了历史和当前字段值的混合在同一页上(!)。我认为,这对我来说是最令人困惑的一个方面,它展示了从未在一个页面上共存的价值观组合。在 Chrome 中查看源代码始终显示最新的副本。我说的是下面精确提炼示例的行为,而不是它们的一些更复杂的版本。
字段一回显内部计数器并忽略用户输入。无论它是否是只读的,它的行为方式都是一样的奇怪。
字段二回显用户输入。我通常将字段一复制或附加到它。
视图.php
<?php
session_start();
header('Cache-Control:private,no-store,no-cache,must-revalidate,post-check=0,pre-check=0');
header('Pragma: no-cache');
$cval = !isset($_SESSION['counter']) ? 0 : $_SESSION['counter'];
$word = !isset($_SESSION['word']) ? '' : htmlentities($_SESSION['word'],ENT_QUOTES,'UTF-8',FALSE);
echo <<<HTM
<pre>
<form method='POST' action='post.php'>
<input type='text' name='count' value='$cval'/>
<input type='text' name='word' value='$word'/>
<input type='submit' name='doit' value='Submit'/>
</form>
</pre>
HTM;
?>
post.php
<?php
session_start();
if(!isset($_SESSION['counter'])):
$_SESSION['counter'] = 1;
else:
$_SESSION['counter'] += 1;
endif;
$_SESSION['word'] = !isset($_POST['word']) ? '' : $_POST['word'];
header('Location: view.php');
?>
如果我开始备份历史记录,Chrome 倾向于显示最新的字段一值,但显示历史字段二值。有时它在两者上都显示历史。如果没有这种差异,我认为阻止服务器(在配对网络上)或代理缓存页面是失败的。
如果我添加一个“过期:-1”标题,它会做同样的事情。
我可以处理识别陈旧的表格;我似乎不能做的是阻止用户到达或提交一个。view.php 上递增的 GET 参数将防止不可预知的缓存视图,但会在所有浏览器中创建明确的历史记录,并且只会邀请人们向后转动棘轮。
为什么会发生这种情况,是否可以修复?