2008-11-04 98 views
3

我有一个网页x.php(在我的网站的密码保护区),其中有一种形式,它使用POST方法发送的表单数据并打开x.php#abc按钮。这工作得很好。浏览器后退按钮恢复空字段

但是,如果用户决定在Internet Explorer 7中导航回来,原始x.php中的所有字段将被清除,并且所有内容都必须重新输入。我无法在会话中保存发布的信息,我正试图了解如何让IE7以我想要的方式行事。

我搜索了网页,发现答案表明HTTP头应包含显式缓存信息。目前,我试过这个:

session_name("FOO"); 
session_start(); 
header("Pragma: public"); 
header("Expires: Fri, 7 Nov 2008 23:00:00 GMT"); 
header("Cache-Control: public, max-age=3600, must-revalidate"); 
header("Last-Modified: Thu, 30 Oct 2008 17:00:00 GMT"); 

及其变体。没有成功。用WireShark这样的工具查看返回的头文件,告诉我Apache确实遵守我的头文件。

所以我的问题是:我做错了什么?

回答

11

IE 自动保留在返回按钮点击表格的内容,只要:

  • 你没有破坏cacheing与无缓存杂注或类似
  • 有问题的表单字段不是由脚本动态创建的

您似乎有缓存在手中,所以我猜测后者可能适用。 (正如mkoeller所说,如果页面处于最后几次点击后,Firefox可以避免这个问题,通过保持页面本身的活动时间超过屏幕上的时间,但是这是可选的,Firefox将恢复到与IE和其他页面相同的行为浏览器一旦你浏览了几页,并且已经过期了)

如果你从脚本onload创建你自己的表单域,那么浏览器无法知道新的输入控件是与旧实例“相同”,因此无法使用先前提交的值填写它。在这种情况下,如果您希望它与后退按钮配合良好,则必须开始在客户端上存储数据。

然后,您必须使用某种状态键,以便每组数据都与页面的一个实例绑定,否则会通过同一窗体的多个实例或在窗体上打开两个浏览器选项卡一旦会严重混淆你的剧本。

而且然后你开始收集大量的数据,如果他们是大单,如果你正在使用的客户端的存储机制是饼干,你可以开始丢失数据,以及发送每个HTTP请求加载不必要的状态废话。其他客户端存储机制可用,但它们是特定于浏览器的。

简而言之:做好动态生成的表单是一个巨大的痛苦,如果可以的话可能是最好的避免。在脚本可见的页面上隐藏窗体,从而允许浏览器执行他们的字段记忆魔术而不是给你任务,通常要容易得多。

+1

尼斯的答案,但对我来说,这个问题必须在别处:我的表格是服务器端生成的,页面上没有任何JavaScript,没有`onload`处理等,所以我真的不明白发生了什么事情! – 2008-11-04 13:22:28

+0

嗯......好吧,我也没有 - 你有一个公开的网址,我们可以看看吗? – bobince 2008-11-04 13:29:49

+0

是的,http://www.epsitec.ch/xxx/buy/full-a - 等一下,如果我添加尾随.htm到该URL,一切工作正常!所以我的问题是由重写规则造成的,它以某种方式混淆了IE7的缓存! – 2008-11-04 13:44:38

3

Firefox做这种缓存。正如我理解你的问题,你希望IE7行为与Firefox的方式。我认为这是不可能的。

Firefox和IE7在解释后退按钮方面有所不同。

Firefox将显示前一页的DOM树,因为它是在页面离开前最后一次显示的。也就是说,所有表单数据仍将包含在表单的输入字段中。但是在点击后退按钮时你不会看到onload事件。

IE7将根据从服务器收到的响应再次呈现该页面。因此,表单是emtpy(除非最初由服务器发送默认值),但您会看到一个onload事件。

2

我捅了一下,这是一个很难的问题。它也是动态修改内容的主要麻烦。您访问该页面,JavaScript会用您的指令扩充它,然后转到下一页并返回,并且javascript已经忘记了。而且没有办法简单地更新页面服务器端,因为页面是从缓存中出来的。

所以我设计了一个后退按钮缓存断路器。

它的邪恶和糟糕的网络,但它使网页能够表现人们如何期望他们的行为,而不是在整个地方神奇翘曲。

<script type="text/javascript">//<!-- <![CDATA[ 
(function(){ 
    if(document.location.hash === "") 
    { 
     document.location.hash="_"; 
    } 
    else 
    { 
     var l = document.location; 
     var myurl = (l.protocol + "//" + l.hostname + l.pathname + l.search); 
     document.location = myurl; 
    } 
})(); 
//]]> --></script> 

这会做一点神奇之处,它会检测您正在/正在/正在查看的页面是否从缓存中加载或未加载。

如果第一次出现,它会检测到“无散列”,并在页面url中添加“#_”。 如果你第一次在那里(即:不是直接链接到页面),页面上已经有#_,所以它将其删除,并在删除它时触发页面重新加载。

1

您可以在字段中使用autocomplete =“off”。 这样,浏览器不会缓存这些值,因此当用户单击后退按钮时,这些值将不会填充到表单中。

3

在试图进一步缩小问题的范围时,我找到了问题的原因。我使用的是由Apache重写的URL(即,我总是访问我的页面,作为http://foo.com/page,由Apache映射到http://foo.com/page.htm)。只要我指定正确的HTTP标头(Cache-Control,Expires等),使用真正的 URL解决了问题并使IE7开心。

以下是我在PHP代码的输出头做这似乎让快乐与缓存中的所有浏览器:

function emitConditionalGet($timestamp) 
{ 
    // See also http://www.mnot.net/cache_docs/ 
    // and code sample http://simonwillison.net/2003/Apr/23/conditionalGet/ 

    $gmdate_exp = gmdate('D, d M Y H:i:s', time() + 1) . ' GMT'; 
    $last_modified = gmdate('D, d M Y H:i:s', $timestamp) . ' GMT'; 
    $etag   = '"'.md5($last_modified).'"'; 

    // If the client provided any of the if-modified-since or if-none-match 
    // infos, take them into account: 

    $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) 
         ? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) : false; 
    $if_none_match  = isset($_SERVER['HTTP_IF_NONE_MATCH']) 
         ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])  : false; 

    if (!$if_modified_since && !$if_none_match) 
    { 
     return; // the client does not cache anything 
    } 

    if ($if_none_match && $if_none_match != $etag) 
    { 
     return; // ETag mismatch: the page changed! 
    } 
    if ($if_modified_since && $if_modified_since != $last_modified) 
    { 
     return; // if-modified-since mismatch: the page changed! 
    } 

    // Nothing changed since last time client visited this page. 

    header("HTTP/1.0 304 Not Modified"); 
    header("Last-Modified: $last_modified"); 
    header("ETag: $etag"); 
    header("Cache-Control: private, max-age=1, must-revalidate"); 
    header("Expires: $gmdate_exp"); 
    header("Pragma: private, cache"); 
    header("Content-Type: text/html; charset=utf-8"); 
    exit; 
} 

function emitDefaultHeaders($timestamp) 
{ 
    $gmdate_exp = gmdate('D, d M Y H:i:s', time() + 1) . ' GMT'; 
    $last_modified = gmdate('D, d M Y H:i:s', $timestamp) . ' GMT'; 
    $etag   = '"'.md5($last_modified).'"'; 

    header("Last-Modified: $last_modified"); 
    header("ETag: $etag"); 
    header("Cache-Control: private, max-age=1, must-revalidate"); 
    header("Expires: $gmdate_exp"); 
    header("Pragma: private, cache"); 
    header("Content-Type: text/html; charset=utf-8"); 
} 

function getTimestamp() 
{ 
    // Find out when this page's contents last changed; in a static system, 
    // this would be the file time of the backing HTML/PHP page. Add your 
    // own logic here: 
    return filemtime($SCRIPT_FILENAME); 
} 

// ... 

$timestamp = getTimestamp(); 
emitConditionalGet($timestamp); 
emitDefaultHeaders($timestamp); //previously, this variable was mistyped as "$timestaml"