Zwischenspeichert Safari unter iOS 6 $ .ajax-Ergebnisse?

1072

Seit dem Upgrade auf iOS 6 können wir in der Webansicht von Safari $.ajaxAnrufe zwischenspeichern. Dies erfolgt im Kontext einer PhoneGap-Anwendung, sodass Safari WebView verwendet wird. Unsere $.ajaxAufrufe sind POSTMethoden und wir haben den Cache auf false gesetzt {cache:false}, aber dies geschieht immer noch. Wir haben versucht TimeStamp, den Headern manuell ein hinzuzufügen , 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 etwas heißt:

getNewRecordID(intRecordType)

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

Muss in Apples Eile sein, um iOS 6 eindrucksvoll mitzumachen. Sie waren zu zufrieden mit den Cache-Einstellungen. Hat jemand anderes dieses Verhalten unter iOS 6 gesehen? Wenn ja, was genau verursacht es?


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

getNewRecordID(intRecordType, strTimestamp)

und übergeben Sie dann immer auch einen TimeStampParameter und verwerfen Sie diesen Wert einfach auf der Serverseite. Dies umgeht das Problem. Ich hoffe, das hilft einer anderen armen Seele, die wie ich 15 Stunden mit diesem Thema verbringt!

user1684978
quelle
190
Das ist absolut schockierend. Wir haben auch nur ein paar Stunden damit verbracht herauszufinden, was gerade nicht mehr funktioniert. Unser AJAX-Login, das einen POST ausführt (und Header hat, um auch das Caching zu verhindern), wird von Safari zwischengespeichert, sodass es nur den gleichen JSON zurückgibt, den es beim letzten Mal gemacht hat, ohne den Server zu testen ... unglaublich! Wir müssen einen Fix hacken, aber Sie sollten niemals einen POST zwischenspeichern, es ist verrückt.
Kieran
16
Veröffentlichen Sie Ihre Lösung als Antwort und nicht als Aktualisierung der Frage.
ChrisF
50
POST-Anforderungen sind nicht idempotent, was bedeutet, dass sie nicht zwischengespeichert werden sollten, es sei denn, die Antwort empfiehlt dies ausdrücklich über ihre Antwortheader.
James M. Greene
6
Melden Sie einen Fehler unter bugreport.apple.com an, damit Apple dies behebt . Ich habe das gleiche getan.
Mathias Bynens
11
Mark Nottingham (Vorsitzender der IETF HTTPbis-Arbeitsgruppe) schrieb heute einen interessanten Blog-Beitrag darüber: mnot.net/blog/2012/09/24/caching_POST
Benjamin Brizzi

Antworten:

447

Nach einigem Nachforschen stellt sich heraus, dass Safari unter iOS6 POSTs zwischenspeichert, die entweder keine Cache-Control-Header oder sogar "Cache-Control: max-age = 0" haben.

Die einzige Möglichkeit, zu verhindern, dass dieses Caching auf globaler Ebene stattfindet, anstatt zufällige Abfrageringe am Ende von Serviceaufrufen hacken zu müssen, besteht darin, "Cache-Control: no-cache" festzulegen.

Damit:

  • Keine Cache-Kontrolle oder Expires-Header = iOS6 Safari wird zwischengespeichert
  • Cache-Control max-age = 0 und ein sofortiges Expires = iOS6 Safari wird zwischengespeichert
  • Cache-Kontrolle: 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 die entsprechenden Cache-Control- oder Expires-Headerfelder. Die Antwort 303 (siehe Andere) kann jedoch verwendet werden, um den Benutzeragenten anzuweisen, eine zwischengespeicherte Ressource abzurufen.

Theoretisch können Sie also POST-Antworten zwischenspeichern ... wer wusste. Aber noch kein anderer Browserhersteller hat jemals gedacht, dass dies eine gute Idee wäre. Dies berücksichtigt jedoch NICHT das Caching, wenn keine Cache-Control- oder Expires-Header gesetzt sind, sondern nur, wenn einige gesetzt sind. Es muss also ein Fehler sein.

Im Folgenden wird beschrieben, was ich im rechten Teil meiner Apache-Konfiguration verwende, um auf die gesamte API abzuzielen, da ich in diesem Fall eigentlich nichts zwischenspeichern möchte, auch nicht. Was ich nicht weiß, ist, wie man dies 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 dann der Fall ist, wenn der POST identisch 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 paar 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
Kieran
quelle
7
Ich sehe, wohin Apple damit geht, aber wir sehen zwischengespeicherte Antworten auf POST-Anfragen, selbst wenn unsere Antworten keine Cache-Control- oder Expires-Header enthielten. Ist diese Instanz iOS6 sollte nicht jede Anfrage zwischenspeichern und senden. Das passiert nicht.
Kango_V
138
Der von Ihnen angegebene Teil der HTTP-Spezifikation rechtfertigt das Caching-Verhalten von iOS 6 nicht. Das Standardverhalten sollte darin bestehen, POST-Antworten nicht zwischenzuspeichern (dh wenn der Header "Cache-Control" nicht definiert ist). Das Verhalten verstößt gegen die Spezifikation und sollte als Fehler angesehen werden. Jeder, der XML / JSON-API-Webdienste erstellt, sollte seine POST-Antworten mit "Cache-Steuerung: kein Cache" dekorieren, um dieses Problem zu umgehen.
David H
39
POST-Anforderungen sind nicht idempotent, was bedeutet, dass sie nicht zwischengespeichert werden sollten, es sei denn, die Antwort empfiehlt dies ausdrücklich über ihre Antwortheader.
James M. Greene
4
Wie David sagt, ist es 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 zwischengespeichert wird. Bitte bearbeiten Sie Ihre Antwort.
Matthew Flaschen
3
Weiß jemand, wie lange das Ergebnis auf einem Gerät zwischengespeichert ist? Ich habe versucht, Safari zu beenden und mein Telefon neu zu starten, aber es wird 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, die das Problem einmal hatten, dauern wird, bis es verschwindet. Nicht jeder wird daran denken, seinen Cache zu
leeren
146

Ich hoffe, dass dies für andere Entwickler von Nutzen sein kann, die ihren Kopf gegen die Wand schlagen. Ich habe festgestellt, dass eine der folgenden Möglichkeiten Safari unter iOS 6 daran hindert, die POST-Antwort zwischenzuspeichern:

  • Hinzufügen von [Cache-Steuerung: kein Cache] in den Anforderungsheadern
  • Hinzufügen eines variablen URL-Parameters wie der aktuellen Zeit
  • Hinzufügen von [Pragma: No-Cache] in den Antwortheadern
  • Hinzufügen von [Cache-Steuerung: kein 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 vielen meiner Serverantworten den Header [pragma: no-cache] hinzu.

Wenn Sie die oben genannte Lösung verwenden, beachten Sie, dass alle von Ihnen getätigten Aufrufe von $ .ajax (), die auf global: false festgelegt sind, NICHT die in $ .ajaxSetup () angegebenen Einstellungen verwenden. Daher müssen Sie die Header erneut hinzufügen.

Dave
quelle
4
Dies ist DIE RICHTIGE Lösung für den Fehler. Der Fehler ist, dass iOS 6 POST-Anforderungen aus dem Cache bearbeitet, anstatt sie an den Server zu senden. Der Fehler besteht nicht darin, dass Antworten von POST-Anforderungen zwischengespeichert werden (was zulässig ist). Verwenden Sie diese Lösung, wenn Sie weiterhin Antworten auf POST-Anforderungen wünschen, die für nachfolgende GET-Anforderungen an diesen URI aus dem Cache abgerufen wurden.
Nicholas Shanks
2
Das funktioniert bei mir, aber ich verstehe nicht wie. Ich hatte bereits cache: false in meinem ajaxSetup angegeben und mir die Anforderungsheader angesehen, die sich auf Cache-Control: no-cache und Pragma: no-cache beschränken - aber es wird immer noch auf dem iPad zwischengespeichert. Wenn ich dann Header hinzufüge: {"Cache-Control": "No-Cache"} in ajaxSetup, verdoppelt sich der Cache-Control-Header zu "No-Cache, No-Cache" - und stoppt das Caching. Was passiert hier?
Tom W Hall
Funktioniert einwandfrei - Sie können der Anfrage auch als Parameter $ .ajax hinzufügen ({Typ: 'POST', Header: {'Cache-Kontrolle': 'Kein Cache'} usw.})
George Filippakos
Was ist [Pragma: kein Cache]? Wofür wird der Pragma-Schlüssel verwendet?
Zakdances
Ich denke auch, dass dies der beste Ansatz ist und keine Problemumgehung mit einem zusätzlichen Parameter. Wir haben dies nur für die Anrufe hinzugefügt, bei denen wir es benötigt haben. Für Anrufe, die immer die gleiche Rendite haben, ist das Caching wahrscheinlich eine gute Sache für den Endbenutzer.
Germankiwi
67

Einfache Lösung für alle Ihre Webdienstanforderungen, 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()
    }));
});

Weitere Informationen zum jQuery-Vorfilteraufruf finden Sie hier .

Wenn Sie jQuery nicht verwenden, überprüfen Sie die Dokumente für die Bibliothek Ihrer Wahl. Sie können ähnliche Funktionen haben.

Baz1nga
quelle
3
Es funktioniert nicht für mich, Server antwortet: "Ungültiger primitiver JSON: timeStamp" asp.net / iis 7.5
Alexandre
3
Was ist mit dem $ .ajax ({"Cache": false ...})? funktioniert es, wenn ein _ = [TIMESTAMP] angehängt wird? (Ich besitze kein solches Gerät, um es zu testen)
Karussell
Ich habe eine vollständige Implementierung der von Karussell vorgeschlagenen Lösung veröffentlicht. Siehe meine Antwort unten.
Sam Shiles
1
@ Karussell. Ich habe gerade versucht, $ .ajax ({"cache": false ...}) zu setzen. Dies behebt das Problem für POST-Anforderungen unter iOS6 nicht. Vermutlich, weil JQuery gemäß den Dokumenten davon ausgeht, dass kein Browser dumm genug ist, um Post-Anfragen zwischenzuspeichern. "Mit POST abgerufene Seiten werden nie zwischengespeichert, daher haben die Optionen cache und ifModified in jQuery.ajaxSetup () keine Auswirkungen auf diese Anforderungen."
Brett Hannah
1
Das funktioniert nicht. Post-Parameter werden nicht zusammengeführt. Der Beitrag von Dave ist eine bessere Lösung.
Chris Muench
43

Ich hatte gerade dieses Problem auch in einer PhoneGap- Anwendung. Ich habe es mithilfe der JavaScript-Funktion getTime()folgendermaßen gelöst :

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 nett von Apple gewesen, Entwickler über dieses Caching-Problem zu informieren.

Bashevis
quelle
1
Ich wollte die Verwendung {cache:false}als Option für entweder $.post()oder kommentieren $.ajaxSetup(), aber laut den Dokumenten werden diese Argumente ignoriert. jQuery wird Post-Anfragen niemals zwischenspeichern, berücksichtigt jedoch nicht den Browser. Vielleicht wäre eine bessere Option, Anfragen mit einen Zeitstempel hinzuzufügen $.ajaxPrefilter().
Fwielstra
Ich verbringe fast 5 Stunden damit, dieses Problem zu beheben, und schließlich reicht das Hinzufügen eines Zeitstempels aus function send_ajax(my_data,refresh) . Siehe
rusly
42

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

Das hat bei mir funktioniert:

public WebService()
{
    HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    ...
}
Tadej
quelle
2
Vielen Dank! Ich wurde verrückt, um herauszufinden, warum sich das iPhone so anders verhält als jede andere Plattform. Diese ASP.NET-spezifische Lösung hat mir eine Menge Zeit gespart.
Mark Brittingham
Hat unter iOS6 nicht funktioniert, siehe meine Antwort gegen Ende des Threads
Brian Ogden
1
Bitte!!!! Stellen Sie eine Bedingung, um dies nur auf IOS 6 anzuwenden. Der Inhaltscache ist für jede Anwendung von entscheidender Bedeutung.
Alexandre
24

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");

In PHP :

header('cache-control: no-cache');
goker.cebeci
quelle
15

Aus meinem eigenen Blog-Beitrag iOS 6.0, in dem Ajax-POST-Anfragen zwischengespeichert werden :

So beheben Sie das Problem: 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.
kiranvj
quelle
2
Ein gutes No-Cache-Attribut für .NET stackoverflow.com/questions/10011780/…
Aran Mulholland
7

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

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

Platzieren Sie es einfach irgendwo in Ihrem JavaScript-Code (nachdem jQuery geladen wurde und am besten, bevor Sie AJAX-Anforderungen ausführen), und es sollte helfen.

Jonathan
quelle
6

Sie können dieses Problem auch beheben, indem Sie die AjQ- Funktion von jQuery ändern , indem Sie Folgendes (ab 1.7.1) oben in der Ajax-Funktion ausführen (Funktion beginnt in Zeile 7212). Diese Änderung aktiviert die integrierte Anti-Cache-Funktion von jQuery für alle POST-Anforderungen.

(Das vollständige Skript finden Sie unter http://dl.dropbox.com/u/58016866/jquery-1.7.1.js.)

Fügen Sie unter Zeile 7221 ein:

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

Ändern Sie dann Folgendes (beginnend mit 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 : "");
}
Sam Shiles
quelle
4
Es ist kein guter Ansatz, die jQuery oder Code, den Sie nicht besitzen, zu ändern. (Jedes Mal, wenn Sie die Version aktualisieren möchten, müssen Sie die Änderung erneut vornehmen. (Oder ein anderer Entwickler aktualisiert und das Programm funktioniert nicht))
andlrc
Dies ist ein absolut gültiger Ansatz, wenn Sie die schnellstmögliche Lösung benötigen, um Apples Idiotie zu mindern. Diese Lösung wurde verwendet, um das Problem für eine massive Site zu beheben, die täglich Millionen von Treffern erhält, und hat es uns ermöglicht, dies einfach durch Ändern einer Datei zu tun.
Sam Shiles
Sie können es sich ansehen und jQuery.ajaxPrefilerIhre Ajax-Anfrage direkt vor dem Erstellen ändern. Sie können dasselbe mit optimiertem und aktualisiertem sicherem Code archivieren.
Andlrc
1
Das Problem beim preFilter-Ansatz besteht darin, dass Sie den Filter registrieren müssen. Wenn Sie ein gemeinsames Skript haben, das beim Laden jeder Seite ausgeführt wird, ist dies in Ordnung. Wenn Sie dies nicht tun, müssen Sie den PreFilter für jede Seite einrichten, die Ajax verwendet. In dem Szenario, mit dem ich konfrontiert war, hatten wir einen gemeinsamen Speicherort für die JQ-Datei, die als Ressource für mehr als 7 einzelne Websites verwendet wurde. Aufgrund dieses Fehlers haben wir Tausende von Pfund pro Stunde verloren, und der von mir vorgeschlagene Ansatz ermöglichte es uns, ihn durch Ändern einer Datei in kürzester Zeit zu beheben. Ich stimme Ihnen grundsätzlich zu, aber Sie müssen manchmal pragmatisch sein!
Sam Shiles
Sie können es dann erneut am Ende dieser Datei hinzufügen. Gut, dass Sie es gelöst haben, Ihr Unternehmen muss sich für Sie freuen.
Andlrc
5

Eine schnelle Lösung für GWT-RPC-Dienste besteht darin, dies allen Remote-Methoden hinzuzufügen:

getThreadLocalResponse().setHeader("Cache-Control", "no-cache");
Lars Høidahl
quelle
Die meisten von uns haben Hunderte von Remote-Methoden in ihren GWT-Bereitstellungen. Gibt es eine universelle Möglichkeit, den Cache-Steuerungsheader für alle Anforderungen festzulegen?
Dirkoneill
5

Dies ist ein Update der Antwort von Baz1nga. Da options.dataes sich nicht um ein Objekt, sondern um eine Zeichenfolge handelt, habe ich nur auf die Verkettung des Zeitstempels zurückgegriffen:

$.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();
  }
});
Remcoder
quelle
1
Das Hinzufügen von Zeitstempeln ist eine schlechte Idee. Versuchen Sie stattdessen Daves Lösung.
Nicholas Shanks
4

Um dieses Problem für WebApps zu beheben, die dem Startbildschirm hinzugefügt wurden, müssen die beiden am häufigsten bewerteten Problemumgehungen befolgt werden. Das Caching muss auf dem Webserver deaktiviert werden, um zu verhindern, dass neue Anforderungen in Zukunft zwischengespeichert werden, und jeder Post-Anforderung müssen zufällige Eingaben hinzugefügt werden, damit bereits zwischengespeicherte Anforderungen durchlaufen werden. Bitte beziehen Sie sich auf meinen Beitrag:

iOS6 - Gibt es eine Möglichkeit, zwischengespeicherte Ajax-POST-Anforderungen für Webanwendungen zu löschen, die dem Startbildschirm hinzugefügt wurden?

WARNUNG: Für alle, die eine Problemumgehung implementiert haben, indem sie ihren Anforderungen einen Zeitstempel hinzugefügt haben, ohne das Caching auf dem Server zu deaktivieren. Wenn Ihre App zum Startbildschirm hinzugefügt wird, wird JEDE Antwort nach dem Posting zwischengespeichert. Wenn Sie den Safari-Cache löschen, wird sie nicht gelöscht und scheint nicht abzulaufen. Wenn nicht jemand eine Möglichkeit hat, dies zu beheben, scheint dies ein potenzieller Speicherverlust zu sein!

fbader
quelle
Werden alle Antworten in der Datei oder im Speicher des Telefons zwischengespeichert?
Eydun
Dies war bei mir nicht der Fall. Ich habe einen Zeitstempel an meine URL angehängt (keine Post-Parameter) und es funktioniert einwandfrei, sowohl beim Surfen von der Safari als auch beim Speichern auf dem Startbildschirm.
ShadeTreeDeveloper
4

Dinge, die mit einem iPad 4 / iOS 6 für mich NICHT funktioniert haben :

Meine Anfrage enthält: Cache-Control: kein Cache

//asp.net's:
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache)

Cache hinzufügen: false für meinen jQuery-Ajax-Aufruf

 $.ajax(
        {
            url: postUrl,
            type: "POST",
            cache: false,
            ...

Nur das hat den Trick gemacht:

var currentTime = new Date();
var n = currentTime.getTime();
postUrl = "http://www.example.com/test.php?nocache="+n;
$.post(postUrl, callbackFunction);
Brian Ogden
quelle
Wofür ist die Abwahl? Dies ist ein wichtiger Informationscache: false funktioniert weder mit iPad4 / iOS6 noch mit //asp.net: HttpContext.Current.Response.Cache.SetCacheability (HttpCacheability.NoCache)
Brian Ogden
Für die Nachwelt: $.ajax cache: falseHängt ab 2017 die URL an den Abfrageparameter an _=Date.prototype.getTime(), sodass das manuelle Anhängen des Zeitstempels nicht mehr erforderlich sein sollte.
Cowbert
3

Das ist die Lösung für GWT-RPC

class AuthenticatingRequestBuilder extends RpcRequestBuilder 
{
       @Override
       protected RequestBuilder doCreate(String serviceEntryPoint) 
       {
               RequestBuilder requestBuilder = super.doCreate(serviceEntryPoint);           
               requestBuilder.setHeader("Cache-Control", "no-cache");

               return requestBuilder;
       }
}

AuthenticatingRequestBuilder builder = new AuthenticatingRequestBuilder();
((ServiceDefTarget)myService).setRpcRequestBuilder(builder);    
Spiff
quelle
2

Meine Problemumgehung in ASP.NET (Pagemethoden, Webservice usw.)

protected void Application_BeginRequest(object sender, EventArgs e)
{
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
}
Alexandre
quelle
1

Das Hinzufügen von Cache-Buster-Parametern, um die Anforderung anders aussehen zu lassen, scheint eine solide Lösung zu sein. Ich würde jedoch davon abraten, da dies jeder Anwendung schaden würde, die auf dem tatsächlichen Caching beruht. Es ist die bestmögliche Lösung, wenn die APIs die richtigen Header ausgeben, auch wenn dies etwas schwieriger ist als das Hinzufügen von Cache-Bustern zu den Anrufern.

Ivo Jansch
quelle
1
Obwohl ich den meisten Umständen zustimmen würde, würde ich argumentieren, dass die eigentliche Lösung für dieses Problem darin besteht, dass Apple HTTP korrekt implementiert. In diesem Sinne würde ich nicht viele Entwickler beschuldigen, bis dahin die einfachste Lösung implementiert zu haben. Für mich war das Ändern der jquery-Implementierung die einfachste Lösung, da ich eine Änderung vornehmen und sicher sein konnte, dass sie für meine gesamte Site aktiv war.
Sam Shiles
1

Für diejenigen, die verwenden Struts 1, ist hier, wie ich das Problem behoben habe.

web.xml

<filter>
    <filter-name>SetCacheControl</filter-name>
    <filter-class>com.example.struts.filters.CacheControlFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>SetCacheControl</filter-name>
    <url-pattern>*.do</url-pattern>
    <http-method>POST</http-method>
</filter-mapping>

com.example.struts.filters.CacheControlFilter.js

package com.example.struts.filters;

import java.io.IOException;
import java.util.Date;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;

public class CacheControlFilter implements Filter {

        public void doFilter(ServletRequest request, ServletResponse response,
                     FilterChain chain) throws IOException, ServletException {

        HttpServletResponse resp = (HttpServletResponse) response;
        resp.setHeader("Expires", "Mon, 18 Jun 1973 18:00:00 GMT");
        resp.setHeader("Last-Modified", new Date().toString());
        resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");
        resp.setHeader("Pragma", "no-cache");

        chain.doFilter(request, response);
    }

    public void init(FilterConfig filterConfig) throws ServletException {
    }

    public void destroy() {
    }

}
cbmeeks
quelle
1

Ich konnte mein Problem beheben, indem ich eine Kombination aus $ .ajaxSetup verwendete und einen Zeitstempel an die URL meines Posts anhängte (nicht an die Post-Parameter / den Post-Body). Dies basiert auf den Empfehlungen früherer Antworten

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

    $('#myForm').submit(function() {
        var data = $('#myForm').serialize();
        var now = new Date();
        var n = now.getTime();
        $.ajax({
            type: 'POST',
            url: 'myendpoint.cfc?method=login&time='+n,
            data: data,
            success: function(results){
                if(results.success) {
                    window.location = 'app.cfm';
                } else {
                    console.log(results);
                    alert('login failed');
                }
            }
        });
    });
});
ShadeTreeDeveloper
quelle
1

Ich denke, Sie haben Ihr Problem bereits gelöst, aber lassen Sie mich eine Idee zum Web-Caching teilen.

Es ist wahr, dass Sie viele Header in jeder Sprache hinzufügen können, die Sie verwenden, serverseitig, clientseitig, und Sie können viele andere Tricks verwenden, um Web-Caching zu vermeiden, aber denken Sie immer, dass Sie nie wissen können, von wo aus der Client eine Verbindung zu Ihrem Server herstellt. Sie wissen nie, ob er eine Hotel-Hot-Spot-Verbindung verwendet, die Squid oder andere Caching-Produkte verwendet.

Wenn die Benutzer Proxy verwenden, um seine reale Position zu verbergen, usw.… die reale einzige Weg , um zu vermeiden Caching ist der Zeitstempel in der Anfrage auch wenn sie nicht benutzt wird.

Zum Beispiel:

/ajax_helper.php?ts=3211321456

Dann hat nicht jeder Cache-Manager, den Sie übergeben müssen, dieselbe URL im Cache-Repository gefunden und den Seiteninhalt erneut heruntergeladen.

Lanello
quelle
Alte Antwort, aber meine zwei Cent: Dies ist im Allgemeinen ein guter Rat und wird von den meisten kompetenten Webentwicklern verstanden. Wenn Sie jedoch im speziellen Fall von jQuery eine $.ajaxOption festlegen und diese festlegen, {cache:false}fügt jQuery selbst automatisch einen Cache-Busting hinzu hinter den Kulissen, ohne dass Sie jemals etwas anderes tun müssen.
JakeGould
0

Abhängig von der App können Sie das Problem jetzt in iOS 6 mithilfe von Safari> Erweitert> Web Inspector beheben, sodass dies in dieser Situation hilfreich ist.

Schließen Sie das Telefon auf einem Mac an Safari an und verwenden Sie das Entwicklermenü, um Probleme mit der Web-App zu beheben.

Löschen Sie die Website-Daten auf dem iPhone nach dem Update auf iOS6, auch für die App, mithilfe einer Webansicht. Nur eine App hatte ein Problem und dies löste es während des IOS6 Beta-Tests vor langer Zeit, seitdem keine wirklichen Probleme mehr.

Möglicherweise müssen Sie sich auch Ihre App ansehen und NSURLCache in einer WebView in einer benutzerdefinierten App auschecken.

https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSURLCache_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003754

Ich denke, abhängig von der wahren Natur Ihres Problems, der Implementierung usw.

Ref: $ .ajax ruft an

Steven Strauss
quelle
Dies behandelt zwar nicht direkt die ursprüngliche Frage, ist jedoch eine sehr nützliche Information, um Probleme auf Geräten im Allgemeinen beheben zu können. Daher stimme ich darüber ab.
Kris Giesing
0

Ich habe eine Problemumgehung gefunden, die mich neugierig macht, warum es funktioniert. Bevor ich Tadejs Antwort zum ASP.NET-Webdienst las, versuchte ich, etwas zu finden, das funktionieren würde.

Und ich sage nicht, dass es eine gute Lösung ist, aber ich wollte es nur hier dokumentieren.

Hauptseite: Enthält eine JavaScript-Funktion, checkStatus (). Die Methode ruft eine andere Methode auf, die einen jQuery AJAX-Aufruf verwendet, um den HTML-Inhalt zu aktualisieren. Ich habe setInterval verwendet, um checkStatus () aufzurufen. Natürlich bin ich auf das Caching-Problem gestoßen.

Lösung: Verwenden Sie eine andere Seite, um das Update aufzurufen.

Auf der Hauptseite habe ich eine boolesche Variable, runUpdate, festgelegt und dem Body-Tag Folgendes hinzugefügt:

<iframe src="helper.html" style="display: none; visibility: hidden;"></iframe>

In der von helper.html:

<meta http-equiv="refresh" content="5">
<script type="text/javascript">
    if (parent.runUpdate) { parent.checkStatus(); }
</script>

Wenn checkStatus () von der Hauptseite aufgerufen wird, erhalte ich den zwischengespeicherten Inhalt. Wenn ich checkStatus von der untergeordneten Seite aus aufrufe, erhalte ich aktualisierte Inhalte.

CM Kanode
quelle
0

Während meine Anmelde- und Anmeldeseiten in Firefox, IE und Chrome wie ein Zauber wirken ... Ich habe in Safari für IOS und OSX mit diesem Problem zu kämpfen. Vor einigen Monaten habe ich eine Problemumgehung für SO gefunden.

<body onunload="">

ODER über Javascript

<script type="text/javascript">
window.onunload = function(e){
    e.preventDefault();
    return;
};
</script>   

Das ist ein bisschen hässlich, funktioniert aber eine Weile.

Ich weiß nicht warum, aber wenn ich null auf das onunloadEreignis zurückgib, wird die Seite in Safari nicht zwischengespeichert.

Adriano Rosa
quelle
0

Wir haben festgestellt, dass ältere iPhones und iPads, auf denen die iOS-Versionen 9 und 10 ausgeführt werden, gelegentlich falsche AJAX-Ergebnisse liefern, möglicherweise aufgrund der Verringerung der CPU-Geschwindigkeit durch Apple. Bei der Rückgabe des leeren Ergebnisses ruft iOS den Server nicht so auf, als würde ein Ergebnis aus dem Cache zurückgegeben. Die Häufigkeit variiert stark und liegt zwischen 10% und 30% der AJAX-Anrufe.

Die Lösung ist kaum zu glauben. Warten Sie einfach 1s und rufen Sie erneut an. In unseren Tests war nur eine Wiederholung alles, was jemals benötigt wurde, aber wir haben den Code geschrieben, um bis zu viermal aufzurufen. Wir sind uns nicht sicher, ob die Wartezeit von 1 Sekunden erforderlich ist, aber wir wollten nicht riskieren, unseren Server mit wiederholten Anrufen zu belasten.

Wir haben festgestellt, dass das Problem bei zwei verschiedenen AJAX-Aufrufen aufgetreten ist, bei denen verschiedene API-Dateien mit unterschiedlichen Daten aufgerufen wurden. Aber ich mache mir Sorgen, dass es bei jedem AJAX-Anruf passieren könnte. Wir wissen es einfach nicht, weil wir nicht jedes AJAX-Ergebnis überprüfen und nicht jeden Anruf mehrmals auf alten Geräten testen.

Beide Problem-AJAX-Aufrufe verwendeten: POST, Asynchron = true, setRequestHeader = ('Content-Type', 'application / x-www-form-urlencoded')

Wenn das Problem auftritt, wird normalerweise nur ein AJAX-Anruf ausgeführt. Es liegt also nicht an überlappenden AJAX-Aufrufen. Manchmal tritt das Problem auf, wenn das Gerät ausgelastet ist, aber manchmal nicht, und ohne DevTools wissen wir nicht wirklich, was gerade passiert.

iOS 13 tut dies nicht, Chrome oder Firefox nicht. Wir haben keine Testgeräte mit iOS 11 oder 12. Vielleicht könnte jemand anderes diese testen?

Ich stelle dies hier fest, da diese Frage das beste Google-Ergebnis bei der Suche nach diesem Problem ist.

CaptureWiz
quelle
-1

Es funktionierte mit ASP.NET erst, nachdem der pragma:no-cacheHeader in IIS hinzugefügt wurde . Cache-Control: no-cachewar nicht genug.

Boris
quelle
-2

Ich schlage eine Problemumgehung vor, um die Funktionssignatur so zu ändern:

getNewRecordID (intRecordType, strTimestamp) und übergeben Sie dann immer auch einen TimeStamp-Parameter und verwerfen Sie diesen Wert einfach auf der Serverseite. Dies umgeht das Problem.

fred1234
quelle