浏览器后退按钮恢复空字段

发布于 2024-07-09 08:03:35 字数 739 浏览 7 评论 0原文

我有一个网页 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 确实尊重我的标头。

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

I have a web page x.php (in a password protected area of my web site) which has a form and a button which uses the POST method to send the form data and opens x.php#abc. This works pretty well.

However, if the users decides to navigate back in Internet Explorer 7, all the fields in the original x.php get cleared and everything must be typed in again. I cannot save the posted information in a session and I am trying to understand how I can get IE7 to behave the way I want.

I've searched the web and found answers which suggest that the HTTP header should contain explicit caching information. Currently, I've tried this :

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");

and variations thereof. Without success. Looking at the returned headers with a tool such as WireShark shows me that Apache is indeed honouring my headers.

So my question is: what am I doing wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

素手挽清风 2024-07-16 08:03:35

IE在单击后退按钮时自动保留表单内容,只要:

  • 您没有使用无缓存编译指示或类似的方式破坏缓存
  • 相关的表单字段不是由脚本动态创建的

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

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

然后,您必须使用某种状态键控,以便每组数据都与页面的一个实例相关联,否则浏览同一表单的多个实例或同时在表单上打开两个浏览器选项卡将严重混淆你的脚本。

然后然后您开始收集大量数据(如果它们是大表单),并且如果您使用的客户端存储机制是 cookie,您可能会开始丢失数据以及发送每个 HTTP 请求都会产生大量不必要的状态废话。 其他客户端存储机制也可用,但它们是特定于浏览器的。

简而言之:很好地制作动态生成的表单是一个巨大的痛苦,如果可以的话最好避免它。 在页面上有一个隐藏的表单,脚本使其可见,从而允许浏览器发挥其字段记忆魔力,而不是给您任务,通常要容易得多。

IE will retain form contents on a back button click automatically, as long as:

  • you haven't broken cacheing with a no-cache pragma or similar
  • the form fields in question weren't dynamically created by script

You seem to have the cacheing in hand, so I'm guessing the latter may apply. (As mkoeller says, Firefox avoids this problem if the page is in the last few back clicks by keeping the page itself alive for longer than it's on the screen. However this is optional, and Firefox will revert to the same behaviour as IE and other browsers once you've browsed a few pages ahead and it has expired the old one.)

If you're creating your own form fields from script onload, then the browser has no way of knowing that the new input control is ‘the same’ as the old instance, so it can't fill it in with the previously-submitted value. In this case if you want it to play well with the back button you have to start storing data on the client.

Then you have to use some sort of state-keying so that each set of data is tied to exactly one instance of the page, otherwise going through multiple instances of the same form or having two browsers tabs open on the form at once will severely confuse your script.

And then you are starting to collect a lot of data if they're big forms, and if the client-side storage mechanism you're using is cookies you can start to lose data, as well as sending a load of unnecessary state nonsense with every HTTP request. Other client-side storage mechanisms are available but they're browser-specific.

In short: doing dynamically-generated forms nicely is a huge pain and it's probably best avoided if you can. Having a hidden form on the page that a script makes visible, thus allowing browsers to do their field-remembering-magic instead of giving you the task, is typically much easier.

墨小沫ゞ 2024-07-16 08:03:35

在尝试进一步缩小问题范围的同时,我找到了问题的原因。 我使用的 URL 正在被 Apache 重写(即我总是以 http://foo.com/page 访问我的页面,它被 Apache 映射到 http://foo.com /page.htm)。 只要我指定正确的 HTTP 标头(Cache-ControlExpires 等),使用真实 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"

While trying to further narrow down the problem, I've found the cause of my problem. I was using URLs which were being rewritten by Apache (i.e. I always accessed my page as http://foo.com/page which is mapped by Apache to http://foo.com/page.htm). Using the real URLs solved the problem and made IE7 happy, as long as I specify the proper HTTP header (Cache-Control, Expires, etc.).

Here is what I do in the PHP code to output headers which seem to make all browsers happy with the cache:

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"
故人爱我别走 2024-07-16 08:03:35

Firefox 就进行了这种缓存。 据我了解您的问题,您希望 IE7 的行为方式与 Firefox 一样。 我认为这是不可能的。

Firefox 和 IE7 对后退按钮的解释方式有所不同。

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

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

Firefox does this kind of caching. As I understand your question, you want IE7 to behave the way Firefox does. I think that's not possible.

Firefox and IE7 differ on the way they interpret the back button.

Firefox will display the DOM tree of the previous page as it was last displayed before the page was left. That is, all the form data will still be contained in the form's input field. But you won't see an onload event upon hitting the back button.

IE7 will render the page again based upon the response it receives from the server. Thus the form is emtpy (unless there were default values sent by the server originally), but you'll see an onload event.

似梦非梦 2024-07-16 08:03:35

我查了一下,这是一个相当困难的问题。 对于动态修改的内容来说,这也是一个大麻烦。 您访问该页面,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>

这会产生一点魔力,因为它会检测您/当前/正在查看的页面是否是从缓存加载的。

如果您是第一次访问,它会检测到“no hash”,并将“#_”添加到页面网址中。
如果您第一次访问该页面(即:不是该页面的直接链接),则该页面上已经有#_,因此它将删除它,并在删除它的过程中触发页面重新加载。

I poked around and this is quite a hard problem. Its also a major pain in the ass for Dynamically modified content. You visit the page, javascript augments it with your instruction, you go to the next page, and come back, and javascript has forgotten. And there's no way to simply update the page server-side, because the page comes out of cache.

So I devised a back-button-cache-breaker.

Its evil and bad-for-the-web, but it makes it able for pages to behave how people expect them to behave instead of magically warping all over the place.

<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>

This will do a bit of magic in that it detects whether or not the page you are /currently/ viewing was loaded from cache or not.

if you're there the first time, it will detect "no hash" , and add "#_" to the page url.
if you're there for the >1st time ( ie: not a direct link to the page ), the page already has the #_ on it, so it removes it and in the process of removing it, triggers a page reload.

兔小萌 2024-07-16 08:03:35

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

You could use autocomplete="off" in your fields.
This way the values won't be cached by the browser so the values won't be filled in the form when the user clicks the back button.

夜访吸血鬼 2024-07-16 08:03:35

这是一篇旧文章,自那以后发生了很多变化。 尽管如此,我的一个表单遇到了这个问题(但 Chrome 起作用了)。如果返回,它会清除所有信息。 我完全是巧合地找到了解决方法,并且需要在这里分享它,只是因为它太奇怪了。 也许这不是发布此内容的最佳位置,但我们开始吧。

这就是我所拥有的(精简版本并且不起作用。)

<table>
    <form>
    <tr>
        <td><input type="number" value="0"></td>
    </tr>
    </form>
</table>

并且这修复了它(现在可以工作。)将

标记移到 标记。

<form>
<table>
    <tr>
        <td><input type="number" value="0"></td>
    </tr>
</table>
</form>

This is an old post, and much has changed since. None the less, I had this very problem with one of my forms (but with Chrome acting up.) It would clear all the info if going back. I found the workaround by total coincidence and needed to share it here, just because it was so odd. Probably it is not the very best place to post this, but here we go.

This is what I had (a stripped down version and not working.)

<table>
    <form>
    <tr>
        <td><input type="number" value="0"></td>
    </tr>
    </form>
</table>

And this fixed it (now working.) Moving the <form> tag outside of the <table> and the <tr> tag.

<form>
<table>
    <tr>
        <td><input type="number" value="0"></td>
    </tr>
</table>
</form>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文