2012-06-28 10 views
9

Um die Leistung/Reaktionszeit meiner Website zu verbessern, habe ich eine teilweise Seitenladung mit AJAX, replaceState, pushState und einem Popstate Listener implementiert.HTML5 History API Zurück-Schaltfläche mit partiellen Seitenlasten

Ich im Wesentlichen den zentralen Teil meiner Seite (HTML) als mein Statusobjekt in der Geschichte speichern. Wenn ein Link angeklickt wird, fordere ich nur das zentrale Bit der Seite vom Server an (indem ich diese Anfragen mit einem anderen Accept-Header identifiziere) und ersetze ihn durch Javascript. Bei popstate greife ich den vorherigen zentralen Teil und schiebe ihn zurück in den Dom.

Das funktioniert meistens gut, aber ich habe ein bestimmtes Problem gefunden, auf dem ich feststecke. Es ist ein wenig kompliziert zu erklären, daher entschuldige ich mich, wenn das nicht sehr klar ist.

Auf den meisten Seiten gibt es ein Suchformular. Das partielle Laden von Seiten über AJAX erfolgt nur bei GET-Anforderungen, und das Formular führt einen POST aus, der zu einer vollständigen Seitenladung führt.

Wenn ich den folgenden Satz von Seiten navigieren, hat ich am Ende auf einer fehlerhaften Teil-Seite nach oben aus NUR der zentralen Inhalt, ohne von dem umgebenden dom:

startet auf der Startseite (über ganze Seite Last) - eine Suche (post-Redirect-get)
Springt Ergebnisse (über volle Seite laden suchen) - dann Startseite
Returns klicken Sie auf die Homepage (über dynamische get) - klicken Browser zurück
Suche Ergebnisse (von Popstate Listener) - klicken Sie auf Browser zurück
Malformed home pag e.

Wenn die fehlerhafte Homepage angezeigt wird, ist mein Popstate-Listener überhaupt nicht vorhanden.

Was ich denke, geschieht, ist, dass die zweite Ladung (dynamisch, teilweise) der Homepage vom Browser zwischengespeichert wird, und dann, wenn die ganze Seite zurück auftritt, zeigt der Browser nur die zwischengespeicherte partielle Antwort statt die ganze Seite.

Um dies zu beheben, habe ich einen Vary: Accept-Header zur Antwort hinzugefügt, damit die Browser wissen, dass sich der Inhalt basierend auf dem Accept-Header ändern kann. Ich habe auch Cache-Control max-age = 0, Pragma no-cache und ein Ablaufdatum der letzten Zeit zu dem teilweise geladenen Inhalt hinzugefügt, um zu versuchen, den Browser zu zwingen, dies nicht zu cachen, aber nichts davon löst es.

Leider erlaubt meine Firma keinen externen Datenverkehr zu unseren Dev-Servern, daher kann ich Ihnen das Problem nicht zeigen. Ich habe mir hier verschiedene ähnliche Fragen angeschaut, aber keine von ihnen scheint gleich zu sein, und auch die vorgeschlagenen Lösungen scheinen nicht zu funktionieren.

Wenn ich meinen dynamischen GET-Anfragen einen sinnlosen Parameter (blah = blah) hinzufüge, löst dies das Problem. Aber das ist ein hässlicher Hack, den ich lieber nicht machen würde. Dies scheint so zu sein, dass es mit Headers lösbar sein sollte, da ich denke, dass es ein Caching-Problem ist. Kann mir jemand erklären, was vor sich geht?

+0

Quick update - die Header scheinen das Problem in Firefox zu lösen, bestehen aber auf Chrome und iOS Safari (Webkit-Problem vielleicht?) –

+0

Es klingt wie ein Caching-Problem. Das Hinzufügen eines Parameters zu den dynamischen GET-Anfragen erscheint sinnvoll - das ist es, was jquery-pjax tut. –

Antwort

8

Das ist ein Caching-Problem. Wenn der Antwort-Header Cache-Control auf no-cache oder max-age=0 gesetzt ist, tritt das Problem nicht in FF auf (wie Sie gesagt haben), aber es bleibt in Chrome bestehen.

Der Header, der für mich arbeitete, ist Cache-Control: no-store. Dies wird nicht von allen Browsern konsistent implementiert (Sie können Fragen stellen, in denen Sie gefragt werden, was den Unterschied zwischen No-Cache und No-Store darstellt), aber das Ergebnis, das Sie auch in Chrome erwarten.

1

Ich hatte ein ähnliches Problem. Ich baue einen webbasierten Assistenten und benutze jquery ajax, um jeden Schritt zu laden (ASP.NET MVC am Backend).

Die ursprüngliche Route ist so etwas wie/Questions/Show - was lädt die ganze Seite und zeigt die erste Frage (Frage 0). Wenn der Benutzer auf das nächste Bild klickt, führt es eine jquery .load() mit der URL/Questions/Save/0 aus. Dies speichert die Antwort und gibt eine Teilansicht mit der nächsten Frage zurück. Das nächste Speichern führt eine jquery .load() mit/Questions/Save/1 ...

Ich habe History.js implementiert, so dass der Benutzer zurück und vorwärts gehen kann (vor?). Es speichert die Frage Nummer in den Zustandsdaten. Wenn es eine Statusänderung erkennt (und die Frage Nummer des Status unterscheidet sich von dem, was auf der Seite ist), wird eine jquery .load() ausgeführt, um die richtige Frage zu laden.

Zuerst benutzte ich die gleiche Route wie beim Laden der ersten Seite (/ Questions/Show/X wo X die Nummer der Frage ist). Am Backend habe ich festgestellt, ob es sich um eine Ajax-Anfrage handelt, und wenn dies der Fall ist, wird eine Teilansicht anstelle der vollständigen Ansicht zurückgegeben. Hier kam das Problem ähnlich wie bei dir: Angenommen, ich war bei Frage 3, ging zurück, dann weiter, dann ging ich zu www.google.com und dann auf den Zurück-Button. Es zeigte Frage 3, aber es war die Teilansicht - weil der Browser den Teil für diese Route zwischenspeichert.

Meine Lösung bestand darin, eine separate Route für den Ajax-Aufruf zu erstellen:/Questions/Load/X (es verwendete gemeinsamen Code am Back-End). Jetzt mit zwei verschiedenen Routen (/ Fragen/Show für Nicht-Ajax und/Fragen/Load für Ajax), zeigt der Browser die vollständige Seite korrekt in der obigen Situation.

Also könnte eine ähnliche Lösung für Sie arbeiten ... d. H. Zwei verschiedene Routen für Ihre Homepage - eine für die ganze Seite und eine für eine teilweise Seite. Ich hoffe, das hilft.

0

Wenn ein Link Ich bitte nur das zentrale Bit der Seite vom Server (identifiziert diese Anforderungen mit einem anderen Header Accept) und es mit Javascript geklickt wird ersetzen.

Ehrfürchtig. Das ist der REST-gerechte Weg, es zu tun. Aber es gibt noch etwas zu tun, um es zum Laufen zu bringen: Fügen Sie einen Vary Header zur Antwort hinzu.

Vary: Accept 

Das teilt dem Browser mit, dass eine Anfrage mit einem anderen Accept-Header eine andere Antwort erhalten könnte. Da die beiden Anforderungen unterschiedliche Accept-Header verwenden, werden der Browser (und alle Caching-Proxys) die Antworten separat zwischenspeichern.

Im Gegensatz zur Einstellung Cache-Control: no-store können Sie weiterhin Caching verwenden.