Zwischenspeichert Safari unter iOS 6 $.ajax-Ergebnisse?
Lesezeit: 10 Minuten
Benutzer1684978
Seit dem Upgrade auf iOS 6 sehen wir, dass sich die Webansicht von Safari die Freiheit des Cachings nimmt $.ajax Anrufe. Dies steht im Kontext einer PhoneGap-Anwendung, also wird Safari WebView verwendet. Unsere $.ajax Anrufe sind POST Methoden und wir haben den Cache auf false gesetzt {cache:false}, aber das passiert immer noch. Wir haben versucht, a manuell hinzuzufügen TimeStamp zu den Headern, aber es hat nicht geholfen.
Wir haben weitere Nachforschungen angestellt und festgestellt, dass Safari nur zwischengespeicherte Ergebnisse für Webdienste zurückgibt, deren Funktionssignatur statisch ist und sich nicht von Aufruf zu Aufruf ändert. Stellen Sie sich zum Beispiel eine Funktion vor, die so heißt:
getNewRecordID(intRecordType)
Diese Funktion erhält immer wieder die gleichen Eingabeparameter, aber die zurückgegebenen Daten sollten jedes Mal anders sein.
Muss in Apples Eile sein, iOS 6 beeindruckend zum Laufen zu bringen, sie waren mit den Cache-Einstellungen zu zufrieden. Hat jemand anderes dieses Verhalten auf iOS 6 gesehen? Wenn ja, woran genau liegt es?
Die Problemumgehung, die wir gefunden haben, bestand darin, die Funktionssignatur so zu ändern:
getNewRecordID(intRecordType, strTimestamp)
und dann immer in a übergehen TimeStamp -Parameter und verwerfen Sie diesen Wert einfach auf der Serverseite. Dies umgeht das Problem.
Das ist absolut schockierend. Wir haben auch gerade ein paar Stunden damit verbracht, herauszufinden, was gerade nicht mehr funktioniert. Unser AJAX-Login, das einen POST durchführt (und Header hat, um auch das Caching zu verhindern), wird von Safari zwischengespeichert, sodass es einfach dasselbe JSON zurückgibt wie beim letzten Mal, ohne den Server überhaupt zu testen … unglaublich! Wir müssen einen Fix hacken, aber Sie sollten niemals einen POST zwischenspeichern, es ist verrückt.
– Kiran
20. September 2012 um 14:55 Uhr
Veröffentlichen Sie Ihre Lösung als Antwort und nicht als Aktualisierung der Frage.
– ChrisF ♦
21. September 2012 um 14:40 Uhr
POST-Anforderungen sind nicht idempotent, was bedeutet, dass sie nicht zwischengespeichert werden sollten wenn nicht die Antwort empfiehlt dies ausdrücklich über ihre Antwortheader.
– James M. Greene
21. September 2012 um 15:14 Uhr
Um Apple dazu zu bringen, dies zu beheben, melden Sie einen Fehler unter bugreport.apple.com. Ich habe das gleiche getan.
– Mathias Bynens
23. September 2012 um 10:13 Uhr
Mark Nottingham (Vorsitzender der IETF-HTTPbis-Arbeitsgruppe) hat heute einen interessanten Blogbeitrag darüber geschrieben: mnot.net/blog/2012/09/24/caching_POST
– Benjamin Brizzi
24. September 2012 um 15:02 Uhr
Kieran
Nach ein wenig Nachforschung stellt sich heraus, dass Safari auf iOS6 POSTs zwischenspeichert, die entweder keine Cache-Control-Header oder sogar “Cache-Control: max-age=0” haben.
Die einzige Möglichkeit, die ich gefunden habe, um zu verhindern, dass dieses Caching auf globaler Ebene stattfindet, anstatt zufällige Abfragezeichenfolgen am Ende von Dienstaufrufen zu hacken, besteht darin, “Cache-Control: no-cache” festzulegen.
Damit:
Keine Cache-Control- oder Expires-Header = iOS6 Safari wird zwischengespeichert
Cache-Control max-age=0 und ein sofortiges Expires = iOS6 Safari wird cachen
Cache-Steuerung: no-cache = iOS6 Safari wird NICHT cachen
Ich vermute, dass Apple dies aus der HTTP-Spezifikation in Abschnitt 9.5 über POST ausnutzt:
Antworten auf diese Methode können nicht zwischengespeichert werden, es sei denn, die Antwort enthält entsprechende Cache-Control- oder Expires-Header-Felder. Die Antwort 303 (See Other) kann jedoch verwendet werden, um den Benutzeragenten anzuweisen, eine zwischenspeicherbare Ressource abzurufen.
Theoretisch können Sie also POST-Antworten zwischenspeichern … wer hätte das gedacht. Aber kein anderer Browser-Hersteller hat bisher jemals daran gedacht, dass dies eine gute Idee wäre. Dies berücksichtigt jedoch NICHT das Caching, wenn keine Cache-Control- oder Expires-Header festgelegt sind, sondern nur, wenn einige festgelegt sind. Es muss also ein Bug sein.
Unten ist, was ich im rechten Teil meiner Apache-Konfiguration verwende, um auf die gesamte API abzuzielen, da ich tatsächlich nichts zwischenspeichern möchte, auch nicht. Was ich nicht weiß, ist, wie man das nur für POSTs einstellt.
Header set Cache-Control "no-cache"
Update: Ich habe gerade bemerkt, dass ich nicht darauf hingewiesen habe, dass dies nur der Fall ist, wenn der POST gleich ist. Ändern Sie also die POST-Daten oder die URL, und es geht Ihnen gut. Sie können also, wie an anderer Stelle erwähnt, einfach einige zufällige Daten zur URL oder ein bisschen POST-Daten hinzufügen.
Update: Sie können den “No-Cache” nur auf POSTs beschränken, wenn Sie dies in Apache wünschen:
SetEnvIf Request_Method "POST" IS_POST
Header set Cache-Control "no-cache" env=IS_POST
Ich verstehe, worauf Apple damit hinaus will, aber wir sehen zwischengespeicherte Antworten auf POST-Anforderungen, selbst wenn unsere Antworten keine Cache-Control- oder Expires-Header enthielten. In diesem Fall sollte iOS6 nicht jede Anfrage zwischenspeichern und senden. Dies geschieht nicht.
– Kango_V
20. September 2012 um 16:52 Uhr
Der von Ihnen zitierte Teil der HTTP-Spezifikation rechtfertigt nicht das Caching-Verhalten von iOS 6. Das Standardverhalten sollte sein, POST-Antworten nicht zwischenzuspeichern (dh wenn der “Cache-Control”-Header nicht definiert ist). Das Verhalten verstößt gegen die Spezifikation und sollte als Fehler betrachtet werden. Jeder, der XML/JSON-API-Webdienste erstellt, sollte seine POST-Antworten mit „Cache-control: no-cache“ ausstatten, um dieses Problem zu umgehen.
– David H
20. September 2012 um 23:06 Uhr
POST-Anforderungen sind nicht idempotent, was bedeutet, dass sie nicht zwischengespeichert werden sollten wenn nicht die Antwort empfiehlt dies ausdrücklich über ihre Antwortheader.
– James M. Greene
21. September 2012 um 15:13 Uhr
Wie David sagt, ist dies eine klare Verletzung des von Ihnen zitierten Satzes. Wenn es keine “Cache-Control- oder Expires-Header-Felder” gibt, sind entsprechende solche Header offensichtlich nicht enthalten. Ihre eigene Untersuchung zeigt jedoch, dass es in diesem Szenario zwischenspeichert. Bitte bearbeiten Sie Ihre Antwort.
– Matthäus Flaschen
22. September 2012 um 6:16 Uhr
Weiß jemand, wie lange das Ergebnis auf einem Gerät zwischengespeichert wird? Ich habe versucht, Safari zu beenden und mein Telefon neu zu starten, aber es ist immer noch zwischengespeichert. Ich weiß, dass es mit dem Löschen des Browser-Cache funktioniert, aber ich frage mich, wie lange es für Benutzer dauern wird, die das Problem einmal hatten, bevor es verschwindet. Nicht jeder wird daran denken, seinen Cache zu leeren …
– Daniel Hallqvist
25. September 2012 um 18:22 Uhr
Ich hoffe, dass dies für andere Entwickler von Nutzen sein kann, die hier ihren Kopf gegen die Wand schlagen. Ich habe festgestellt, dass eines der folgenden Dinge verhindert, dass Safari unter iOS 6 die POST-Antwort zwischenspeichert:
Hinzufügen [cache-control: no-cache] in den Request-Headern
Hinzufügen eines variablen URL-Parameters wie der aktuellen Uhrzeit
Hinzufügen [pragma: no-cache] in den Antwortheadern
Hinzufügen [cache-control: no-cache] in den Antwortheadern
Meine Lösung war die folgende in meinem Javascript (alle meine AJAX-Anfragen sind POST).
Ich füge auch die hinzu [pragma: no-cache] Header zu vielen meiner Serverantworten.
Wenn Sie die obige Lösung verwenden, beachten Sie, dass alle von Ihnen getätigten $.ajax()-Aufrufe, die auf global: false gesetzt sind, NICHT die in $.ajaxSetup() angegebenen Einstellungen verwenden, sodass Sie die Header erneut hinzufügen müssen.
Dies ist DIE RICHTIGE Lösung für den Fehler. Der Fehler ist, dass iOS 6 POST-Anfragen aus seinem Cache bedient, anstatt sie an den Server zu senden. Der Fehler besteht nicht darin, dass Antworten von POST-Anforderungen zwischengespeichert werden (was zulässig ist). Wenn Sie weiterhin Antworten auf POST-Anforderungen für nachfolgende GET-Anforderungen an diesen URI aus dem Cache abrufen möchten, verwenden Sie diese Lösung.
– Nikolaus Shanks
12. November 2012 um 16:32 Uhr
Das funktioniert bei mir, aber ich verstehe nicht wie. Ich hatte bereits cache: false in meinem ajaxSetup angegeben, und wenn ich mir die Anforderungsheader ansehe, läuft das auf Cache-Control: no-cache und Pragma: no-cache hinaus – aber es wird immer noch auf dem iPad zwischengespeichert. Wenn ich dann Header hinzufüge: { “cache-control”: “no-cache” } in ajaxSetup, verdoppelt es den Cache-Control-Header zu “no-cache, no-cache” – und stoppt das Caching. Was passiert hier?
– Tom W. Halle
26. November 2012 um 22:18 Uhr
Funktioniert einwandfrei – man kann der Anfrage auch als Parameter $.ajax({type: ‘POST’, headers: { ‘cache-control’: ‘no-cache’ }, etc.}) hinzufügen
– George Filippakos
2. Januar 2013 um 13:05 Uhr
Was ist [pragma: no-cache]? Wofür wird der Pragmaschlüssel verwendet?
– Zak-Tänze
19. März 2013 um 20:34 Uhr
Ich denke auch, dass dies der beste Ansatz ist, anstatt eine Problemumgehung mit einem zusätzlichen Parameter. Wir haben dies nur bei den Anrufen hinzugefügt, wo wir es brauchten, für Anrufe, die immer die gleiche Antwort haben, ist das Caching wahrscheinlich eine gute Sache für den Endbenutzer.
– deutschkiwi
20. Mai 2013 um 22:37 Uhr
Baz1nga
Einfache Lösung für alle Ihre Webdienstanfragen, vorausgesetzt, Sie verwenden jQuery:
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
// you can use originalOptions.type || options.type to restrict specific type of requests
options.data = jQuery.param($.extend(originalOptions.data||{}, {
timeStamp: new Date().getTime()
}));
});
Lesen Sie mehr über den jQuery-Vorfilteraufruf Hier.
Wenn Sie jQuery nicht verwenden, überprüfen Sie die Dokumentation für die Bibliothek Ihrer Wahl. Sie können ähnliche Funktionen haben.
Bei mir funktioniert es nicht, der Server antwortet: “Invalid primitive JSON: timeStamp” asp.net / iis 7.5
– Alexandre
24. September 2012 um 0:10 Uhr
Was ist mit $.ajax({ “cache”: false …}) ? wird es funktionieren, wenn es ein _= anhängt[TIMESTAMP]? (Ich besitze kein solches Gerät um es zu testen)
– Karußell
24. September 2012 um 12:59 Uhr
Ich habe eine vollständige Implementierung der von Karussell vorgeschlagenen Lösung gepostet. Siehe meine Antwort unten.
– Sam Shiles
27. September 2012 um 14:45 Uhr
@Karussell. Habe gerade versucht, $.ajax({ “cache”: false …}) zu setzen. Dadurch wird das Problem für POST-Anforderungen unter iOS6 nicht behoben. Vermutlich, weil JQuery gemäß ihrer Dokumentation davon ausgeht, dass kein Browser dumm genug ist, um Post-Requests zwischenzuspeichern. “Mit POST abgerufene Seiten werden nie zwischengespeichert, daher haben die Cache- und ifModified-Optionen in jQuery.ajaxSetup() keine Auswirkung auf diese Anfragen.”
– Brett Hannah
2. Oktober 2012 um 11:02 Uhr
Das funktioniert nicht. Post-Parameter werden nicht zusammengeführt. Der Beitrag von Dave ist eine bessere Lösung.
– Chris Münch
15. Oktober 2012 um 23:33 Uhr
Bashevis
Ich hatte dieses Problem auch gerade in a PhoneGap Anwendung. Ich habe es mit der JavaScript-Funktion gelöst getTime() auf folgende Art:
var currentTime = new Date();
var n = currentTime.getTime();
postUrl = "http://www.example.com/test.php?nocache="+n;
$.post(postUrl, callbackFunction);
Ich habe ein paar Stunden damit verschwendet, das herauszufinden. Es wäre nett von Apple gewesen, die Entwickler über dieses Caching-Problem zu informieren.
Ich hatte das gleiche Problem mit einer Webapp, die Daten vom ASP.NET-Webservice erhielt
Das hat bei mir funktioniert:
public WebService()
{
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
...
}
Danke sehr! Ich wurde verrückt, als ich versuchte herauszufinden, warum sich das iPhone so anders verhielt als jede andere Plattform. Diese ASP.NET-spezifische Lösung hat mir eine Menge Zeit gespart.
– Mark Brittingham
11. November 2012 um 18:14 Uhr
Hat unter iOS6 nicht funktioniert, siehe meine Antwort am Ende des Threads
– Brian Ogden
29. April 2013 um 6:41 Uhr
Bitte!!!! Setzen Sie eine Bedingung, um dies nur auf IOS 6 anzuwenden, der Inhaltscache ist für jede Anwendung von entscheidender Bedeutung.
– Alexandre
8. April 2015 um 22:27 Uhr
Endlich habe ich eine Lösung für mein Upload-Problem.
In JavaScript:
var xhr = new XMLHttpRequest();
xhr.open("post", 'uploader.php', true);
xhr.setRequestHeader("pragma", "no-cache");
Danke sehr! Ich wurde verrückt, als ich versuchte herauszufinden, warum sich das iPhone so anders verhielt als jede andere Plattform. Diese ASP.NET-spezifische Lösung hat mir eine Menge Zeit gespart.
– Mark Brittingham
11. November 2012 um 18:14 Uhr
Hat unter iOS6 nicht funktioniert, siehe meine Antwort am Ende des Threads
– Brian Ogden
29. April 2013 um 6:41 Uhr
Bitte!!!! Setzen Sie eine Bedingung, um dies nur auf IOS 6 anzuwenden, der Inhaltscache ist für jede Anwendung von entscheidender Bedeutung.
So beheben Sie das Problem: Es gibt verschiedene Methoden, um das Caching von Anfragen zu verhindern. Die empfohlene Methode ist das Hinzufügen eines No-Cache-Headers. So wird es gemacht.
jQuery:
Suchen Sie nach iOS 6.0 und setzen Sie den Ajax-Header wie folgt:
$.ajaxSetup({ cache: false });
ZeptoJS:
Suchen Sie nach iOS 6.0 und setzen Sie den Ajax-Header wie folgt:
Das ist absolut schockierend. Wir haben auch gerade ein paar Stunden damit verbracht, herauszufinden, was gerade nicht mehr funktioniert. Unser AJAX-Login, das einen POST durchführt (und Header hat, um auch das Caching zu verhindern), wird von Safari zwischengespeichert, sodass es einfach dasselbe JSON zurückgibt wie beim letzten Mal, ohne den Server überhaupt zu testen … unglaublich! Wir müssen einen Fix hacken, aber Sie sollten niemals einen POST zwischenspeichern, es ist verrückt.
– Kiran
20. September 2012 um 14:55 Uhr
Veröffentlichen Sie Ihre Lösung als Antwort und nicht als Aktualisierung der Frage.
– ChrisF
♦
21. September 2012 um 14:40 Uhr
POST-Anforderungen sind nicht idempotent, was bedeutet, dass sie nicht zwischengespeichert werden sollten wenn nicht die Antwort empfiehlt dies ausdrücklich über ihre Antwortheader.
– James M. Greene
21. September 2012 um 15:14 Uhr
Um Apple dazu zu bringen, dies zu beheben, melden Sie einen Fehler unter bugreport.apple.com. Ich habe das gleiche getan.
– Mathias Bynens
23. September 2012 um 10:13 Uhr
Mark Nottingham (Vorsitzender der IETF-HTTPbis-Arbeitsgruppe) hat heute einen interessanten Blogbeitrag darüber geschrieben: mnot.net/blog/2012/09/24/caching_POST
– Benjamin Brizzi
24. September 2012 um 15:02 Uhr