Entwickler-Ecke

Internet / Netzwerk - Den Browser dazu bringen, die Seite neu zu laden


Gausi - Sa 04.10.08 17:21
Titel: Den Browser dazu bringen, die Seite neu zu laden
Ich hab da mit den Indys einen kleinen Webserver gebaut, bei dem ich noch ein kleines Problem habe.

Und zwar ändern sich die Daten, die der Server bei Anfrage einer speziellen Seite liefern soll, recht schnell. Der Browser benutzt aber manchmal/oft die alte Seite, die er wohl aus dem Cache nimmt, wenn ich über einen Link auf einer anderen Seite die Seite wieder aufrufe.

Wie kann ich den Browser dazu bringen, dass er bei Klick auf einen Link die Seite dahinter neu lädt und nicht die Daten aus dem Cache nimmt?


Hidden - Sa 04.10.08 17:26

Gibt es keinen Befehl, um den Cache zu lehren :?:


Gausi - Sa 04.10.08 17:33

Naja, ich will ja nicht den Cache leeren. Ich will nur, dass der Browser irgendwie merkt, dass da was neues hinter dem Link steckt.

Beispiel: Wenn ich hier im posting.php oben auf den Link zu delphi-forum.de/index.php klicke, dann lädt mein Browser die Startseite vom Forum neu, obwohl ich grade eben noch dadrauf war. Wie kann ich dieses Verhalten mit den Indys nachbauen?


BenBE - Sa 04.10.08 18:21

Du musst in der Seite ein Pragma: no-cache mitsenden, um dem Browser mitzuteilen, dass die Seite nicht gespeichert werden soll.

Alternativ kannst Du einen Last-Modified-Header senden, damit der Browser bei Dir nachfragt, wann sich die Seite geändert hat und ob er den Inhalt komplett neu laden soll.


Narses - Sa 04.10.08 18:23

Moin!

user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:
Ich will nur, dass der Browser irgendwie merkt, dass da was neues hinter dem Link steckt.
Ich hab das hier in einem älteren PHP-Projekt gefunden:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
<?php

header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Datum aus Vergangenheit
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
// immer geändert
header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache"); // HTTP/1.0
Vielleicht kommst du damit weiter. :nixweiss:

Muss aber im Commandhandler in die Headerdaten gesetzt werden, nicht in den Content, IIRC. :?

cu
Narses


BenBE - Sa 04.10.08 18:33

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
Moin!

user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:
Ich will nur, dass der Browser irgendwie merkt, dass da was neues hinter dem Link steckt.
Ich hab das hier in einem älteren PHP-Projekt gefunden:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
<?php

header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Datum aus Vergangenheit
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
// immer geändert
header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache"); // HTTP/1.0
Vielleicht kommst du damit weiter. :nixweiss:

@user profile iconNarses: Das sind exakt jegliche Header, die man benötigt:


Zusätzlich kann man auch noch mit ETags rumspielen, das ist aber i.d.R. nicht nötig.

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
Muss aber im Commandhandler in die Headerdaten gesetzt werden, nicht in den Content, IIRC. :?

cu
Narses

Der header-Befehl von PHP erzeugt einen Antwort-Header, ist doch klar, dass der nicht im Content-Bereich erscheint. Man kann die oben gesendeten Werte über entsprechende META-http-equiv-Angaben auch noch mal im ausgelieferten Dokument verankern.


Gausi - Sa 04.10.08 18:47

Ok, das ist schonmal was. Mit
AResponseInfo.CustomHeaders.Add('Cache-Control: no-store, no-cache, must-revalidate'); scheint das schon zu funktionieren. Sind die anderen Header unbedingt nötig? Ok, die alte Version des Cache-Dingens sehe ich noch ein, aber sind Expires und Modified auch nötig?

Wäre egal, wenn ich das auch noch einfügen müsste, jetzt geht es ums Verstehen. ;-)


BenBE - Sa 04.10.08 19:04

Der Expires-Header gibt wie oben geschrieben an, bis wann eine Seite gültig ist. Angenommen, man erlaubt dem Browser die Seite zu cachen, dann würde der Browser erst nach erreichen des Expires-Headers wieder beim Server nachfragen, ob sich was geändert hat. Nun gibt es bei dieser Anfrage zwei Möglichkeiten:

  1. Der Browser sendet den alten Last-Modified-Header in einer "If-Modified-Since"-Anfrage (oder den Expires-Header, wenn kein Last-Modified vorhanden ist) und erfährt, dass sich trotz Ablauf der Antwortgültigkeit nichts geändert hat: Der Browser zeigt seinen bisherigen Content weiter an, fragt aber bei jedem weiteren Aufruf beim Server immer erneut an, wann sich wieder was geändert hat. Der Server sendet in seiner Antwort KEINEN Content-Bereich mit, da der Client diesen ja eh bereits kennt
  2. Der Browser sendet einen If-Modified-Since-Header und bekommt vom Server mitgeteilt, dass eine neuere Version verfügbar ist. In diesem Fall sendet der Server auch gleich die neue Version des Dokuments. Der Browser übernimmt diese Information in seinen Cache, sofern er erlaubt ist, dies zu tun.


Warum sollte man nun diese Header nutzen: Da man im Idealfall Content sparen kann UND die Rechenzeit, um die Antwort zu generieren. Daher sollte man, wenn ein Neuaufbau der Seite nur in unregelmäßigen Abständen nötig ist, das Caching von HTTP nutzen, wenn dies möglich ist ...


Gausi - Sa 04.10.08 19:29

Um den Traffic gehts mir eher weniger. Das sind in der Regel weniger als 10kb, und wenn man halbwegs was in der Birne hat, nutzt man die Funktion nur im LAN. Der Zugriff nur nach Passworteingabe tut da auch noch was bei.
Um die Serverleistung auch nicht - das Ding ist sowieso eigentlich für nur einen Nutzer ausgelegt - wäre vollkommen unsinnig, wenn 10 Leute gleichzeitig an dem Player rumfummeln. ;-)

Und zu deinen Erklärungen: Der untere Teil in Narses' Auflistungen verbietet dem Browser (so wie ich das verstehe), den Cache zu nutzen. - Wozu also dann die Modified/Expires-Header?

Oder sind das einfach zwei Möglichkeiten, das Problem zu lösen? Das eine etwas eleganter, das andere mit Gewalt?


Yogu - Sa 04.10.08 19:37

phpBB3 regelt den Download der Anhang-Dateien so:


PHP-Code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
  // let's see if we have to send the file at all
  $last_load   =  isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? strtotime(trim($_SERVER['HTTP_IF_MODIFIED_SINCE'])) : false;
  if (strpos(strtolower($browser), 'msie 6.0') === false)
  {
    if ($last_load !== false && $last_load <= $stamp)
    {
      if (@php_sapi_name() === 'CGI')
      {
        header('Status: 304 Not Modified'true304);
      }
      else
      {
        header('HTTP/1.0 304 Not Modified'true304);
      }
      // seems that we need those too ... browsers
      header('Pragma: public');
      header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', time() + 31536000));
      exit();
    }
    else
    {
      header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $stamp) . ' GMT');
    }

Das mit IE6 verstehe ich nicht, wahrscheinlich kann der das ganze nicht, aber sonst ist der Code ganz verständlich. Das exit(); heißt, dass die Datei nicht versendet werden soll, danach kommt nämlich der eigentliche Dateitransfer.


BenBE - Sa 04.10.08 19:48

@Yogu: Der IE6 hat einen Bug bei der Behandlung der Cache-Header, wenn nicht die richtigen Statuscodes gesendet werden, daher die Sonderbehandlung. Da wird nix andres gemacht, als explizit einen HTTP-Status 304 zu senden, der besagt, dass sich nix verändert hat.

@Gausi: Wieso nicht ;-) Collaborative Music Listening :mrgreen:

Zu der Geschichte Expires vs. Cache Control:
Übergeordnet sind zuerst einmal die Pragma- und Cache-Control-Direktiven, die angeben ob überhaupt, und wenn ja, was gecacht werden darf. Darauf aufbauend müssen, wenn der Cache verwendet wird, informationen über die Gültigkeitsdauer, bzw. evtl. nötige Updates eingetragen werden, was mit Hilfe der Last-Modified\Expires-Header geschieht.

Nun zum Problem: Leider interpretieren nicht alle Browser alle Header immer unter allen Umständen korrekt (siehe IE6 ;-)). Daher sollte man i.d.R. alle Header senden, um ein Fallback zu haben, wenn die Interpretation eines einzelnen Header-Wertes einmal fehlschlagen sollte.