Кнопка возврата браузера восстанавливает пустые поля - PullRequest
4 голосов
/ 04 ноября 2008

У меня есть веб-страница 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 действительно соблюдает мои заголовки.

Итак, мой вопрос: что я делаю не так?

Ответы [ 5 ]

11 голосов
/ 04 ноября 2008

IE будет автоматически сохранять содержимое формы при нажатии кнопки "Назад", пока:

  • вы не нарушили кэширование с помощью прагмы no-cache или аналогичной
  • рассматриваемые поля формы не создавались динамически скриптом

Кажется, у вас в руках кеширование, так что я полагаю, что последнее применимо. (Как говорит mkoeller, Firefox избегает этой проблемы, если страница находится в нескольких последних щелчках назад, поддерживая саму страницу дольше, чем на экране. Однако это необязательно, и Firefox вернется к тому же поведению, что и IE и другие. браузеры, как только вы просмотрели несколько страниц вперед и у них истек срок действия старой.)

Если вы создаете свои собственные поля формы из скрипта при загрузке, то браузер не может знать, что новый элемент управления вводом «совпадает» со старым экземпляром, поэтому он не может заполнить его ранее представленное значение. В этом случае, если вы хотите, чтобы он хорошо работал с кнопкой «назад», вы должны начать сохранять данные на клиенте.

Затем вы должны использовать какую-то кодировку состояния, чтобы каждый набор данных был привязан ровно к одному экземпляру страницы, иначе проходил бы через несколько экземпляров одной и той же формы или одновременно открывал две вкладки браузера в форме сильно запутает ваш сценарий.

И , затем вы начинаете собирать много данных, если они большие формы, и если механизм хранения на стороне клиента, который вы используете, это куки, вы также можете начать терять данные как отправка множества ненужных бессмысленных состояний с каждым HTTP-запросом. Доступны другие механизмы хранения на стороне клиента, но они зависят от браузера.

Короче говоря: правильно создавать динамически генерируемые формы - это огромная боль, и, вероятно, ее лучше избегать, если вы можете. Наличие скрытой формы на странице, которую сценарий делает видимой, что позволяет браузерам выполнять магию запоминания полей вместо того, чтобы давать вам задачу, как правило, гораздо проще.

4 голосов
/ 04 ноября 2008

Пытаясь еще больше сузить проблему, я нашел причину своей проблемы. Я использовал URL-адреса, которые были переписаны Apache (то есть я всегда обращался к своей странице как http://foo.com/page, которая сопоставляется Apache с http://foo.com/page.htm). Использование реальных URL-адресов решило проблему и сделало IE7 счастливым, если я укажу правильный HTTP-заголовок (Cache-Control, Expires и т. Д.).

Вот что я делаю в коде 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"
3 голосов
/ 04 ноября 2008

Firefox выполняет этот вид кэширования. Как я понимаю ваш вопрос, вы хотите, чтобы IE7 вел себя так же, как Firefox. Я думаю, что это невозможно.

Firefox и IE7 различаются по способу интерпретации кнопки «назад».

Firefox отобразит дерево DOM предыдущей страницы так, как оно отображалось в последний раз перед тем, как страница была оставлена. То есть все данные формы все равно будут содержаться в поле ввода формы. Но вы не увидите событие onload после нажатия кнопки "Назад".

IE7 отобразит страницу снова на основе ответа, полученного от сервера. Таким образом, форма emtpy (если только изначально не было значений, отправленных сервером), но вы увидите событие onload.

2 голосов
/ 04 ноября 2008

Я ковырялся, и это довольно сложная проблема. Это также большая боль в заднице для динамически модифицированного контента. Вы посещаете страницу, 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-й раз (то есть: не прямая ссылка на страницу), на странице уже есть #_, поэтому она удаляет ее и в процессе удаления вызывает перезагрузку страницы.

1 голос
/ 04 ноября 2008

Вы можете использовать autocomplete = "off" в ваших полях. Таким образом, значения не будут кэшироваться браузером, поэтому значения не будут заполнены в форме, когда пользователь нажимает кнопку возврата.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...