POST请求发送Refresh头的位置会使Firefox创建GET请求,但仍然保留POST数据



考虑以下代码;它基本上是一个表单,通过HTTP POST发送一些数据。当POST数据到达时,发送Refresh HTTP报头。

<?php
if (!empty($_POST))
{
    header("Refresh: 5; URL=http://$_SERVER[SERVER_NAME]$_SERVER[REQUEST_URI]");
}
?>
<!doctype html>
<form method=post>
    <input type=hidden name=foo value=bar>
    <input type=submit>
</form>
<?php
echo "The location was requested using the HTTP $_SERVER[REQUEST_METHOD] method; $_POST = ".var_export($_POST, 1);
?>

现在,这样做:

  1. 在Firefox浏览器中打开(我在这里创建了一个演示;我在Debian上使用6.0.1)。
  2. 提交表单显然,浏览器执行了一个HTTP POST请求。请注意,Refresh HTTP头与响应一起出现。
  3. 等待5秒。现在Refresh标头正在被应用,位置将被重定向到自身。
  4. Firefox执行GET请求。这绝对是GET,因为Firebug和PHP的$_SERVER['REQUEST_METHOD']都这么说。
  5. F5键。由于最后一个执行的HTTP请求是一个GET请求,因此可能会丢失以前请求的所有POST数据。但是,出现一个对话框,要求我重新发送POST数据:

要显示此页面,Iceweasel必须发送重复先前执行的任何操作(如搜索或订单确认)的信息。

所以,我的问题是-为什么POST数据还在这里?这是一个错误还是故意的行为?请注意,使用以下任何一种都会导致POST数据的丢失(预期的行为):

  • Location标头代替Refresh
  • Refresh头的URL=参数值不同(用户将被重定向到另一个位置)。
  • 另一个浏览器(我测试过Internet Explorer 9.0.2和Chromium 6.0)。

这既不是bug,也不是预期的行为。这样做的原因是没有任何HTTP rfc定义的名为Refresh:的头(最明显的是RFC1945和RFC2616没有提到它)。这意味着,虽然大多数浏览器确实实现了Refresh标头,就好像它是一个元刷新,但没有预期的行为,可以假设在所有浏览器中是相同的。

环顾StackOverflow和互联网,似乎Refresh:标头(像许多东西一样)是网景在互联网早期发明的,并被所有人采用。虽然许多Netscape的任意设计(如Javascript)后来被采用为行业标准,但Refresh:标头并没有,因为HTTP已经用3xx响应码提供了这个功能。

总而言之,不同的浏览器处理它的方式不同,这并不奇怪,因为没有标准告诉浏览器的开发人员确切地如何处理它。关于在应用程序中使用标题-不要。简单明了。使用3xx重定向。这就是它们的作用。如果您使用它是因为您需要在超时后刷新页面,请使用<meta>刷新-虽然这现在已被正式弃用,但它应该以相同的方式处理。

最新更新