Frage Ist Safari auf iOS 6 in der Lage, $ .ajax-Ergebnisse zwischenzuspeichern?


Seit dem Upgrade auf iOS 6 können wir in der Web-Ansicht von Safari Caching durchführen $.ajax Anrufe. Dies ist im Kontext einer PhoneGap-Anwendung, so dass es die Safari WebView verwendet. Unser $.ajax Anrufe sind POST Methoden und wir haben Cache auf false festgelegt {cache:false}, aber das passiert immer noch. Wir haben versucht, manuell ein TimeStamp zu den Header, aber es hat nicht geholfen.

Wir haben mehr Nachforschungen angestellt und festgestellt, dass Safari nur zwischengespeicherte Ergebnisse für Webdienste zurückgibt, die eine Funktionssignatur aufweisen, die statisch ist und sich nicht von Anruf zu Anruf ändert. Stellen Sie sich zum Beispiel eine Funktion vor, die so etwas heißt:

getNewRecordID(intRecordType)

Diese Funktion empfängt dieselben Eingabeparameter immer wieder, aber die Daten, die sie zurückgibt, sollten jedes Mal anders sein.

Muss in Apples Eile sein, um iOS 6 eindrucksvoll mitzappen zu lassen, wurden sie mit den Cache-Einstellungen zu glücklich. Hat jemand anderes dieses Verhalten auf iOS 6 gesehen? Wenn ja, was genau verursacht es?


Die Problemumgehung, die wir fanden, bestand darin, die Funktionssignatur so zu ändern:

getNewRecordID(intRecordType, strTimestamp)

und gib dann immer eine ein TimeStamp Parameter, und einfach diesen Wert auf der Serverseite verwerfen. Dies funktioniert um das Problem herum. Ich hoffe, dass dies einer anderen armen Seele hilft, die wie ich 15 Stunden in diesem Thema verbringt!


1029
2017-09-20 06:07


Ursprung


Antworten:


Nach ein wenig Nachforschungen stellt sich heraus, dass Safari auf iOS6 POSTs zwischenspeichert, die entweder keine Cache-Control-Header oder gar "Cache-Control: max-age = 0" haben.

Die einzige Möglichkeit, dieses Zwischenspeichern auf globaler Ebene zu verhindern, anstatt willkürliche Querystrings am Ende von Serviceaufrufen zu hacken, besteht darin, "Cache-Control: no-cache" zu setzen.

Damit:

  • No Cache-Control oder Expires Header = iOS6 Safari wird zwischengespeichert
  • Cache-Control max-age = 0 und ein sofortiges Expires = iOS6 Safari wird zwischengespeichert
  • Cache-Control: no-cache = iOS6 Safari wird NICHT zwischengespeichert

Ich vermute, dass Apple dies aus der HTTP-Spezifikation in Abschnitt 9.5 über POST nutzt:

Antworten auf diese Methode können nicht zwischengespeichert werden, es sei denn die Antwort      enthält entsprechende Cache-Control- oder Expires-Headerfelder. Jedoch,      Die 303-Antwort (Siehe andere) kann verwendet werden, um den Benutzeragenten zu verweisen      eine cachefähige Ressource abrufen.

In der Theorie können Sie POST-Antworten zwischenspeichern ... wer wusste. Aber kein anderer Browserhersteller hat jemals gedacht, dass dies eine gute Idee wäre. Aber das berücksichtigt nicht das Caching, wenn keine Cache-Control- oder Expires-Header gesetzt sind, nur wenn einige gesetzt sind. Also muss es ein Fehler sein.

Unten ist, was ich im richtigen Bit meiner Apache-Konfiguration verwende, um die gesamte API anzusprechen, weil ich eigentlich nichts zwischenspeichern will, sogar bekomme. Was ich nicht weiß ist, wie man das nur für POSTs einstellt.

Header set Cache-Control "no-cache"

Update: Habe gerade gemerkt, dass ich nicht darauf hingewiesen habe, dass es nur dann, wenn der POST gleich ist, also irgendwelche POST-Daten oder URLs ändern und alles in Ordnung ist. Sie können also, wie an anderer Stelle erwähnt, nur 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 möchten:

SetEnvIf Request_Method "POST" IS_POST
Header set Cache-Control "no-cache" env=IS_POST

434
2017-09-20 16:06



Ich hoffe, dass dies für andere Entwickler nützlich sein kann, die hier ihren Kopf gegen die Wand schlagen. Ich habe festgestellt, dass Safari verhindert, dass Safari auf iOS 6 die POST-Antwort zwischenspeichert:

  • Hinzufügen von [cache-control: no-cache] in den Anforderungsheadern
  • Hinzufügen eines variablen URL-Parameters wie der aktuellen Uhrzeit
  • Hinzufügen von [Pragma: No-Cache] in den Antwortheadern
  • Hinzufügen von [cache-control: no-cache] in den Antwortheadern

Meine Lösung war die folgende in meinem Javascript (alle meine AJAX-Anfragen sind POST).

$.ajaxSetup({
    type: 'POST',
    headers: { "cache-control": "no-cache" }
});

Außerdem füge ich den [pragma: no-cache] -Header zu vielen meiner Serverantworten hinzu.

Wenn Sie die obige Lösung verwenden, beachten Sie, dass alle $ .ajax () -Aufrufe, die auf global gesetzt sind, verwendet werden: false verwendet NICHT die in $ .ajaxSetup () angegebenen Einstellungen, daher müssen Sie die Header erneut hinzufügen.


143
2017-10-12 09:56



Einfache Lösung für alle Ihre Web-Service-Anfragen, 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-Prefilter-Aufruf Hier.

Wenn Sie jQuery nicht verwenden, überprüfen Sie die Dokumente für Ihre bevorzugte Bibliothek. Sie können ähnliche Funktionalität haben.


64
2017-09-21 08:53



Ich hatte das gleiche Problem mit einer Webanwendung, die Daten vom ASP.NET Webservice erhielt

Das hat für mich funktioniert:

public WebService()
{
    HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    ...
}

40
2017-09-20 21:28



Ich hatte gerade dieses Problem auch in einem TelefonGap 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 verbracht, das herauszufinden. Es wäre schön von Apple gewesen, Entwickler über dieses Caching-Problem zu informieren.


40
2017-09-20 07:34



Schließlich 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");

Im PHP:

header('cache-control: no-cache');

22
2017-09-22 10:16



Von meinem eigenen Blogpost iOS 6.0 Caching Ajax POST-Anfragen:

So beheben Sie es: Es gibt verschiedene Methoden, um das Zwischenspeichern von Anforderungen 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:

$.ajax({
    type: 'POST',
    headers : { "cache-control": "no-cache" },
    url : ,
    data:,
    dataType : 'json',
    success : function(responseText) {…}

Serverseite

Java:

httpResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");

Stellen Sie sicher, dass Sie dies oben auf der Seite hinzufügen, bevor Daten an den Client gesendet werden.

.NETZ

Response.Cache.SetNoStore();

Oder

Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);

PHP

header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1.
header('Pragma: no-cache'); // HTTP 1.0.

14
2017-11-14 06:02



Dieser JavaScript-Snippet funktioniert hervorragend mit jQuery und jQuery Mobile:

$.ajaxSetup({
    cache: false,
    headers: {
        'Cache-Control': 'no-cache'
    }
});

Platziere es einfach irgendwo in deinem JavaScript-Code (nachdem jQuery geladen wurde und am besten bevor du AJAX-Anfragen machst) und es sollte helfen.


7
2018-01-25 22:11



Ein schneller Work-Around für GWT-RPC-Dienste besteht darin, dies zu allen Remote-Methoden hinzuzufügen:

getThreadLocalResponse().setHeader("Cache-Control", "no-cache");

5
2017-10-16 22:57



Dies ist ein Update von Baz1nga's Antwort. Schon seit options.data ist kein Objekt, sondern eine Zeichenfolge, die ich gerade zum Verketten des Zeitstempels verwendet habe:

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
  if (originalOptions.type == "post" || options.type == "post") {

    if (options.data && options.data.length)
      options.data += "&";
    else
      options.data = "";

    options.data += "timeStamp=" + new Date().getTime();
  }
});

5
2017-10-25 12:32



Sie können dieses Problem auch beheben, indem Sie die Option ändern jQuery  Ajax Funktion, indem Sie die folgenden Funktionen (ab 1.7.1) am Anfang der Ajax-Funktion ausführen (Funktion beginnt bei Zeile 7212). Diese Änderung aktiviert die integrierte Anti-Cache-Funktion von jQuery für alle POST-Anfragen.

(Das vollständige Skript ist verfügbar unter http://dl.dropbox.com/u/58016866/jquery-1.7.1.js.)

Fügen Sie unterhalb der Zeile 7221 ein:

if (options.type === "POST") {
    options.cache = false;
}

Dann modifiziere folgendes (ab Zeile ~ 7497).

if (!s.hasContent) {
    // If data is available, append data to URL
    if (s.data) {
        s.url += (rquery.test(s.url) ? "&" : "?") + s.data;
        // #9682: remove data so that it's not used in an eventual retry
        delete s.data;
    }

    // Get ifModifiedKey before adding the anti-cache parameter
    ifModifiedKey = s.url;

    // Add anti-cache in URL if needed
    if (s.cache === false) {
        var ts = jQuery.now(),
        // Try replacing _= if it is there
        ret = s.url.replace(rts, "$1_=" + ts);

        // If nothing was replaced, add timestamp to the end.
        s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
    }
}

Zu:

// More options handling for requests with no content
if (!s.hasContent) {
    // If data is available, append data to URL
    if (s.data) {
        s.url += (rquery.test(s.url) ? "&" : "?") + s.data;
        // #9682: remove data so that it's not used in an eventual retry
        delete s.data;
    }

    // Get ifModifiedKey before adding the anti-cache parameter
    ifModifiedKey = s.url;
}

// Add anti-cache in URL if needed
if (s.cache === false) {
    var ts = jQuery.now(),
    // Try replacing _= if it is there
    ret = s.url.replace(rts, "$1_=" + ts);

    // If nothing was replaced, add timestamp to the end.
    s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
}

5
2017-09-27 14:30