Safari sur iOS 6 met-il en cache les résultats $ .ajax?

1072

Depuis la mise à niveau vers iOS 6, nous voyons la vue Web de Safari prendre la liberté de mettre en cache les $.ajaxappels. C'est dans le contexte d'une application PhoneGap donc elle utilise Safari WebView. Nos $.ajaxappels sont des POSTméthodes et nous avons mis le cache sur false {cache:false}, mais cela se produit toujours. Nous avons essayé d'ajouter manuellement un TimeStampen-tête mais cela n'a pas aidé.

Nous avons fait plus de recherches et avons découvert que Safari ne renvoie que les résultats mis en cache pour les services Web qui ont une signature de fonction qui est statique et ne change pas d'un appel à l'autre. Par exemple, imaginez une fonction appelée quelque chose comme:

getNewRecordID(intRecordType)

Cette fonction reçoit les mêmes paramètres d'entrée encore et encore, mais les données qu'elle renvoie doivent être différentes à chaque fois.

Doit être dans la hâte d'Apple pour que iOS 6 avance de manière impressionnante, ils sont trop satisfaits des paramètres de cache. Quelqu'un d'autre a-t-il vu ce comportement sur iOS 6? Si oui, quelle en est exactement la cause?


La solution de contournement que nous avons trouvée consistait à modifier la signature de la fonction pour qu'elle ressemble à ceci:

getNewRecordID(intRecordType, strTimestamp)

puis passez toujours un TimeStampparamètre également, et jetez simplement cette valeur du côté serveur. Cela fonctionne autour du problème. J'espère que cela aide une autre pauvre âme qui passe 15 heures sur cette question comme moi!

user1684978
la source
190
C'est absolument choquant. Nous venons également de passer quelques heures à essayer de comprendre ce que quelque chose vient de cesser de fonctionner. Notre connexion AJAX qui effectue un POST (et a des en-têtes pour empêcher la mise en cache aussi) est mise en cache par Safari, donc elle retourne juste le même JSON que la dernière fois sans même essayer le serveur ... incroyable! Nous devrons pirater un correctif, mais vous ne devriez jamais mettre en cache un POST, c'est fou.
Kieran
16
Publiez votre solution comme réponse plutôt que comme mise à jour de la question.
ChrisF
50
Les requêtes POST ne sont pas idempotentes, ce qui signifie qu'elles ne doivent pas être mises en cache à moins que la réponse ne le conseille spécifiquement via ses en-têtes de réponse.
James M. Greene
6
Pour que Apple répare ce problème, déposez un bogue sur bugreport.apple.com . J'ai fait pareil.
Mathias Bynens
11
Mark Nottingham (président du groupe de travail IETF HTTPbis) a écrit un article de blog intéressant à ce sujet aujourd'hui: mnot.net/blog/2012/09/24/caching_POST
Benjamin Brizzi

Réponses:

447

Après un peu d'investigation, il s'avère que Safari sur iOS6 mettra en cache les POST qui n'ont aucun en-tête Cache-Control ou même "Cache-Control: max-age = 0".

La seule façon que j'ai trouvée d'empêcher cette mise en cache de se produire au niveau global plutôt que d'avoir à pirater des chaînes de requête aléatoires sur les appels de fin de service est de définir "Cache-Control: no-cache".

Donc:

  • Aucun en-tête Cache-Control ou Expires = iOS6 Safari mettra en cache
  • Cache-Control max-age = 0 et une expiration immédiate = iOS6 Safari mettra en cache
  • Cache-Control: no-cache = iOS6 Safari ne mettra PAS en cache

Je soupçonne qu'Apple profite de cela à partir de la spécification HTTP dans la section 9.5 sur POST:

Les réponses à cette méthode ne peuvent pas être mises en cache, sauf si la réponse inclut des champs d'en-tête Cache-Control ou Expires appropriés. Cependant, la réponse 303 (Voir Autre) peut être utilisée pour demander à l'agent utilisateur de récupérer une ressource pouvant être mise en cache.

Donc, en théorie, vous pouvez mettre en cache les réponses POST ... qui savait. Mais aucun autre fabricant de navigateur n'a jamais pensé que ce serait une bonne idée jusqu'à présent. Mais cela ne tient PAS compte de la mise en cache lorsqu'aucun en-tête Cache-Control ou Expires n'est défini, uniquement lorsqu'il y en a. Donc ça doit être un bug.

Vous trouverez ci-dessous ce que j'utilise dans la partie droite de ma configuration Apache pour cibler l'ensemble de mon API car, en l'occurrence, je ne veux vraiment rien mettre en cache, même le obtient. Ce que je ne sais pas, c'est comment régler cela juste pour les POST.

Header set Cache-Control "no-cache"

Mise à jour: Je viens de remarquer que je n'ai pas souligné que ce n'est que lorsque le POST est le même, alors changez les données ou l'URL du POST et tout va bien. Vous pouvez donc, comme mentionné ailleurs, simplement ajouter des données aléatoires à l'URL ou un peu de données POST.

Mise à jour: vous pouvez limiter le "no-cache" uniquement aux POST si vous le souhaitez dans Apache:

SetEnvIf Request_Method "POST" IS_POST
Header set Cache-Control "no-cache" env=IS_POST
Kieran
la source
7
Je vois où Apple va avec cela, mais nous voyons des réponses mises en cache aux demandes POST même lorsque nos réponses ne comprenaient aucun en-tête Cache-Control ou Expires. Est-ce que cette instance iOS6 ne doit pas mettre en cache et envoyer chaque demande. Cela n'arrive pas.
Kango_V
138
La partie de la spécification HTTP que vous avez citée ne justifie pas le comportement de mise en cache d'iOS 6. Le comportement par défaut devrait être de ne pas mettre en cache les réponses POST (c'est-à-dire lorsque l'en-tête "Cache-Control" n'est pas défini). Le comportement viole la spécification et doit être considéré comme un bogue. Quiconque construit des services Web api xml / json doit décorer ses réponses POST avec "Cache-control: no-cache" pour contourner ce problème.
David H
39
Les requêtes POST ne sont pas idempotentes, ce qui signifie qu'elles ne doivent pas être mises en cache à moins que la réponse ne le conseille spécifiquement via ses en-têtes de réponse.
James M. Greene
4
Comme le dit David, c'est une violation claire de la phrase que vous avez citée. S'il n'y a pas de "champs d'en-tête Cache-Control ou Expires", ces en-têtes appropriés ne sont évidemment pas inclus. Pourtant, votre propre enquête montre qu'il se cache dans ce scénario. Veuillez modifier votre réponse.
Matthew Flaschen
3
Quelqu'un sait-il combien de temps le résultat est mis en cache sur un appareil? J'ai essayé de tuer Safari et de redémarrer mon téléphone, mais il est toujours en cache. Je sais que cela fonctionne avec la suppression du cache du navigateur, mais je me demande combien de temps cela prendra pour les utilisateurs qui ont déjà eu le problème avant qu'il ne disparaisse. Tout le monde ne pensera pas à vider leur cache ...
Daniel Hallqvist
146

J'espère que cela pourra être utile à d'autres développeurs se cognant la tête contre le mur de celui-ci. J'ai constaté que l'un des éléments suivants empêche Safari sur iOS 6 de mettre en cache la réponse POST:

  • ajout de [cache-control: no-cache] dans les en-têtes de demande
  • ajout d'un paramètre d'URL variable tel que l'heure actuelle
  • ajout de [pragma: no-cache] dans les en-têtes de réponse
  • ajout de [cache-control: no-cache] dans les en-têtes de réponse

Ma solution était la suivante dans mon Javascript (toutes mes demandes AJAX sont POST).

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

J'ajoute également l'en-tête [pragma: no-cache] à plusieurs de mes réponses de serveur.

Si vous utilisez la solution ci-dessus, sachez que tous les appels $ .ajax () que vous effectuez et qui sont définis sur global: false n'utiliseront PAS les paramètres spécifiés dans $ .ajaxSetup (), vous devrez donc ajouter à nouveau les en-têtes.

Dave
la source
4
C'est LA bonne solution au bug. Le bogue est qu'iOS 6 traitera les requêtes POST à ​​partir de son cache au lieu de les envoyer au serveur. Le bogue n'est pas qu'il met en cache les réponses des requêtes POST (ce qui est autorisé). Si vous souhaitez toujours que les réponses aux demandes POST soient extraites du cache pour les demandes GET ultérieures vers cet URI, utilisez cette solution.
Nicholas Shanks
2
Cela fonctionne pour moi, mais je ne comprends pas comment. J'avais déjà spécifié cache: false dans mon ajaxSetup, et en regardant les en-têtes de demande, cela se résume à Cache-Control: no-cache et Pragma: no-cache - mais il sera toujours mis en cache sur l'iPad. Ensuite, lorsque j'ajoute des en-têtes: {"cache-control": "no-cache"} dans ajaxSetup, il double l'en-tête Cache-Control pour qu'il soit "no-cache, no-cache" - et arrête la mise en cache. Qu'est-ce qu'il se passe ici?
Tom W Hall
Fonctionne parfaitement - vous pouvez également ajouter à la demande en tant que paramètre $ .ajax ({type: 'POST', en-têtes: {'cache-control': 'no-cache'}, etc.})
George Filippakos
Qu'est-ce que [pragma: no-cache]? À quoi sert la clé pragma?
zakdances
Je pense également que c'est la meilleure approche, plutôt qu'une solution de contournement avec un paramètre supplémentaire. Nous l'avons ajouté uniquement aux appels où nous en avions besoin, pour les appels qui ont toujours le même retour, la mise en cache est probablement une bonne chose pour l'utilisateur final.
germankiwi
67

Solution simple pour toutes vos demandes de service Web, en supposant que vous utilisez 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()
    }));
});

En savoir plus sur l'appel du préfiltre jQuery ici .

Si vous n'utilisez pas jQuery, consultez les documents de votre bibliothèque de choix. Ils peuvent avoir des fonctionnalités similaires.

Baz1nga
la source
3
Cela ne fonctionne pas pour moi, le serveur répond: "JSON primitif non valide: horodatage" asp.net / iis 7.5
Alexandre
3
qu'en est-il du $ .ajax ({"cache": false ...})? cela fonctionnera-t-il en ajoutant un _ = [TIMESTAMP]? (Je ne possède pas un tel appareil pour le tester)
Karussell
J'ai posté une mise en œuvre complète de la solution proposée par Karussell. Voir ma réponse ci-dessous.
Sam Shiles
1
@Karussell. Je viens d'essayer de définir $ .ajax ({"cache": false ...}). Cela ne résout pas le problème des demandes POST sur iOS6. Vraisemblablement parce que JQuery selon leurs documents suppose qu'aucun navigateur n'est assez stupide pour mettre en cache les demandes de publication. "Les pages récupérées avec POST ne sont jamais mises en cache, donc le cache et les options ifModified dans jQuery.ajaxSetup () n'ont aucun effet sur ces requêtes."
Brett Hannah
1
Ça ne marche pas. Il ne fusionne pas les paramètres de publication. Le message de Dave est une meilleure solution.
Chris Muench
43

Je viens d'avoir ce problème également dans une application PhoneGap . Je l'ai résolu en utilisant la fonction JavaScript getTime()de la manière suivante:

var currentTime = new Date();
var n = currentTime.getTime();
postUrl = "http://www.example.com/test.php?nocache="+n;
$.post(postUrl, callbackFunction);

J'ai perdu quelques heures à comprendre cela. Il aurait été agréable qu'Apple informe les développeurs de ce problème de mise en cache.

Bashevis
la source
1
J'allais commenter l'utilisation {cache:false}en option de l'un $.post()ou de l' autre $.ajaxSetup(), mais selon les documents , ces arguments sont ignorés; jQuery ne mettra jamais en cache les demandes de publication, mais ne tient pas compte du navigateur. Une option plus soignée serait peut-être d'ajouter un horodatage aux requêtes utilisant $.ajaxPrefilter().
fwielstra
je passe presque 5 heures à résoudre ce problème, et enfin l'ajout d'horodatage fera l'affaire function send_ajax(my_data,refresh) . reportez-vous ici stackoverflow.com/questions/14733772/…
rusly
42

J'ai eu le même problème avec une application Web obtenant des données du service Web ASP.NET

Cela a fonctionné pour moi:

public WebService()
{
    HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    ...
}
Tadej
la source
2
Merci beaucoup! J'étais devenu fou en essayant de comprendre pourquoi l'iPhone agissait si différemment de toutes les autres plates-formes. Cette solution spécifique à ASP.NET m'a fait gagner une tonne de temps.
Mark Brittingham
N'a pas fonctionné sur iOS6 voir ma réponse vers la fin du fil
Brian Ogden
1
S'il vous plaît!!!! Mettre une condition pour appliquer cela uniquement sur IOS 6, le cache de contenu est vital pour toute application.
Alexandre
24

Enfin, j'ai une solution à mon problème de téléchargement.

En JavaScript:

var xhr = new XMLHttpRequest();
xhr.open("post", 'uploader.php', true);
xhr.setRequestHeader("pragma", "no-cache");

En PHP :

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

De mon propre article de blog iOS 6.0 mettant en cache les requêtes Ajax POST :

Comment résoudre ce problème: Il existe différentes méthodes pour empêcher la mise en cache des demandes. La méthode recommandée consiste à ajouter un en-tête sans cache. Voilà comment cela se fait.

jQuery:

Vérifiez iOS 6.0 et définissez l'en-tête Ajax comme ceci:

$.ajaxSetup({ cache: false });

ZeptoJS:

Vérifiez iOS 6.0 et définissez l'en-tête Ajax comme ceci:

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

Du côté serveur

Java:

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

Assurez-vous d'ajouter ceci en haut de la page avant d'envoyer des données au client.

.NET

Response.Cache.SetNoStore();

Ou

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
la source
2
Un bon attribut sans cache pour .NET stackoverflow.com/questions/10011780/…
Aran Mulholland
7

Cet extrait JavaScript fonctionne parfaitement avec jQuery et jQuery Mobile:

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

Il suffit de le placer quelque part dans votre code JavaScript (après le chargement de jQuery, et mieux avant de faire des requêtes AJAX) et cela devrait vous aider.

Jonathan
la source
6

Vous pouvez également résoudre ce problème en modifiant jQuery Ajax fonction en procédant comme suit (à partir de 1.7.1) en haut de la fonction Ajax (la fonction commence à la ligne 7212). Cette modification activera la fonction anti-cache intégrée de jQuery pour toutes les requêtes POST.

(Le script complet est disponible sur http://dl.dropbox.com/u/58016866/jquery-1.7.1.js .)

Insérez sous la ligne 7221:

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

Modifiez ensuite ce qui suit (à partir de la ligne ~ 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 : "");
    }
}

À:

// 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
la source
4
Ce n'est pas une bonne approche pour changer le jQuery ou d'ailleurs n'importe quel code que vous ne possédez pas. (Chaque fois que vous souhaitez mettre à jour la version, vous devrez effectuer à nouveau le changement. (Ou un autre développeur met à jour et le programme ne fonctionne pas))
andlrc
C'est une approche parfaitement valable si vous avez besoin de la solution la plus rapide possible pour atténuer l'idiotie d'Apple. Cette solution a été utilisée pour résoudre le problème d'un site massif qui reçoit des millions de visites par jour et elle nous a permis de le faire simplement en modifiant un fichier.
Sam Shiles
Vous pouvez le regarder jQuery.ajaxPrefilervous permet de modifier votre demande ajax juste avant de la faire. Vous pouvez les archiver avec un code plus optimisé et plus sûr.
andlrc
1
Le problème avec l'approche preFilter est que vous devez enregistrer le filtre. Si vous avez un script commun qui s'exécute lorsque chaque page se charge, alors très bien, mais si vous ne le faites pas, vous devrez configurer le pré-filtre pour chaque page qui utilise ajax. Le scénario auquel j'ai fait face, nous avions un emplacement commun pour le fichier JQ qui était utilisé comme ressource pour plus de 7 sites Web individuels. Nous perdions des milliers de livres par heure à cause de ce bogue et l'approche que j'ai suggérée nous a permis de le résoudre dans les plus brefs délais en changeant UN fichier. Je suis d'accord avec vous en principe mais il faut parfois être pragmatique!
Sam Shiles
Vous pouvez ensuite à nouveau l'ajouter à la fin de ce fichier. Bon vous l'avez résolu, votre entreprise doit être heureuse pour vous.
andlrc
5

Une solution rapide pour les services GWT-RPC consiste à ajouter ceci à toutes les méthodes distantes:

getThreadLocalResponse().setHeader("Cache-Control", "no-cache");
Lars Høidahl
la source
La plupart d'entre nous ont des centaines de méthodes distantes dans leurs déploiements GWT. Existe-t-il un moyen universel de définir l'en-tête de contrôle du cache pour toutes les demandes?
dirkoneill
5

Ceci est une mise à jour de la réponse de Baz1nga. Puisque ce options.datan'est pas un objet mais une chaîne, je viens de recourir à la concaténation de l'horodatage:

$.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
la source
1
Ajouter des horodatages est une mauvaise idée, essayez plutôt la solution de Dave.
Nicholas Shanks
4

Afin de résoudre ce problème pour les applications Web ajoutées à l'écran d'accueil, les deux solutions de contournement les plus votées doivent être suivies. La mise en cache doit être désactivée sur le serveur Web pour empêcher la mise en cache de nouvelles demandes et certaines entrées aléatoires doivent être ajoutées à chaque demande de publication pour que les demandes qui ont déjà été mises en cache soient traitées. Veuillez vous référer à mon message:

iOS6 - Existe-t-il un moyen d'effacer les demandes POST ajax mises en cache pour une application Web ajoutée à l'écran d'accueil?

AVERTISSEMENT: à toute personne ayant implémenté une solution de contournement en ajoutant un horodatage à ses demandes sans désactiver la mise en cache sur le serveur. Si votre application est ajoutée à l'écran d'accueil, CHAQUE réponse sera désormais mise en cache, l'effacement du cache safari ne l'efface pas et il ne semble pas expirer. À moins que quelqu'un ait un moyen de l'effacer, cela ressemble à une fuite de mémoire potentielle!

fbader
la source
Toutes les réponses seront-elles mises en cache dans un fichier ou dans la mémoire du téléphone?
Eydun
Ce n'était pas le cas avec moi. J'ai ajouté un horodatage à mon URL (pas de paramètres de publication) et cela fonctionne très bien, à la fois lors de la navigation depuis Safari et lors de l'enregistrement sur l'écran d'accueil.
ShadeTreeDeveloper
4

Choses qui n'ont pas fonctionné pour moi avec un iPad 4 / iOS 6:

Ma demande contenant: Cache-Control: no-cache

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

Ajout de cache: faux à mon appel ajQuery jQuery

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

Seulement cela a fait l'affaire:

var currentTime = new Date();
var n = currentTime.getTime();
postUrl = "http://www.example.com/test.php?nocache="+n;
$.post(postUrl, callbackFunction);
Brian Ogden
la source
À quoi sert le vote négatif? Il s'agit d'un cache d'informations important: false ne fonctionne pas avec iPad4 / iOS6 ni //asp.net: HttpContext.Current.Response.Cache.SetCacheability (HttpCacheability.NoCache)
Brian Ogden
Pour la postérité: à partir de 2017, $.ajax cache: falseajoute l'URL avec le paramètre de requête _=Date.prototype.getTime(), donc l'ajout manuel de l'horodatage ne devrait plus être nécessaire.
cowbert
3

Voilà le travail autour de 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
la source
2

Ma solution de contournement dans ASP.NET (pagemethods, webservice, etc.)

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

Bien que l'ajout de paramètres de cache-buster pour rendre la demande différente semble être une solution solide, je déconseille cela, car cela nuirait à toute application qui repose sur la mise en cache réelle. Faire en sorte que les API produisent les en-têtes corrects est la meilleure solution possible, même si c'est un peu plus difficile que d'ajouter des cache-cache aux appelants.

Ivo Jansch
la source
1
Bien que je sois d'accord avec vous dans la plupart des cas, je dirais que la vraie solution à ce problème est qu'Apple implémente correctement HTTP. Dans cet esprit, je ne blâmerais pas beaucoup de développeurs d'avoir implémenté la solution la plus simple possible jusqu'à ce moment-là. Pour moi, la modification de l'implémentation de jquery était la solution la plus simple car elle m'a permis de faire une modification et d'être sûr qu'elle était active pour l'ensemble de mon site.
Sam Shiles
1

Pour ceux qui utilisent Struts 1, voici comment j'ai résolu le problème.

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
la source
1

J'ai pu résoudre mon problème en utilisant une combinaison de $ .ajaxSetup et en ajoutant un horodatage à l'url de mon message (pas aux paramètres / corps du message). Ceci basé sur les recommandations des réponses précédentes

$(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
la source
1

Je pense que vous avez déjà résolu votre problème, mais permettez-moi de partager une idée sur la mise en cache Web.

Il est vrai que vous pouvez ajouter de nombreux en-têtes dans chaque langue que vous utilisez, côté serveur, côté client, et vous pouvez utiliser de nombreuses autres astuces pour éviter la mise en cache Web, mais pensez toujours que vous ne pouvez jamais savoir d'où le client se connecte à votre serveur, vous ne savez jamais s'il utilise une connexion «Hot-Spot» d'hôtel qui utilise Squid ou d'autres produits de mise en cache.

Si les utilisateurs utilisent un proxy pour cacher sa position réelle, etc… le seul moyen réel d'éviter la mise en cache est l'horodatage de la demande également s'il n'est pas utilisé.

Par exemple:

/ajax_helper.php?ts=3211321456

Ensuite, chaque gestionnaire de cache que vous devez passer n'a pas trouvé la même URL dans le référentiel de cache et a téléchargé à nouveau le contenu de la page.

Lanello
la source
Ancienne réponse, mais mes deux cents: c'est généralement un bon conseil et compris par la plupart des développeurs Web compétents, mais dans le cas spécifique de jQuery, si vous faites un $.ajaxet avez défini les options pour avoir, {cache:false}jQuery lui-même ajoutera automatiquement un contournement du cache dans les coulisses sans que vous ayez besoin de faire autre chose.
JakeGould du
0

Selon l'application, vous pouvez résoudre le problème maintenant dans iOS 6 en utilisant Safari> Avancé> Inspecteur Web, ce qui est utile dans cette situation.

Connectez le téléphone à Safari sur un Mac et utilisez le menu développeur pour résoudre les problèmes liés à l'application Web.

Effacez les données du site Web sur l'iPhone après la mise à jour vers iOS6, y compris celles spécifiques à l'application à l'aide d'une vue Web. Une seule application a eu un problème et cela l'a résolu lors du test de la version bêta d'IOS6, depuis lors, aucun problème réel.

Vous devrez peut-être également consulter votre application, consultez NSURLCache si dans une WebView dans une application personnalisée.

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

Je suppose que cela dépend de la vraie nature de votre problème, de sa mise en œuvre, etc.

Ref: Appels $ .ajax

Steven Strauss
la source
Bien que cela ne réponde pas directement à la question d'origine, ce sont des informations très utiles pour pouvoir résoudre les problèmes sur les appareils en général, donc je vote favorablement.
Kris Giesing
0

J'ai trouvé une solution de contournement qui me rend curieux de savoir pourquoi cela fonctionne. Avant de lire la réponse de Tadej concernant le service Web ASP.NET, j'essayais de trouver quelque chose qui fonctionnerait.

Et je ne dis pas que c'est une bonne solution, mais je voulais juste la documenter ici.

page principale: inclut une fonction JavaScript, checkStatus (). La méthode appelle une autre méthode qui utilise un appel jQuery AJAX pour mettre à jour le contenu html. J'ai utilisé setInterval pour appeler checkStatus (). Bien sûr, j'ai rencontré le problème de la mise en cache.

Solution: utilisez une autre page pour appeler la mise à jour.

Sur la page principale, j'ai défini une variable booléenne, runUpdate, et ajouté ce qui suit à la balise body:

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

Dans le fichier helper.html:

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

Donc, si checkStatus () est appelé depuis la page principale, j'obtiens le contenu mis en cache. Si j'appelle checkStatus depuis la page enfant, j'obtiens un contenu mis à jour.

CM Kanode
la source
0

Alors que mes pages de connexion et d'inscription fonctionnent comme un charme dans Firefox, IE et Chrome ... J'ai eu du mal avec ce problème dans Safari pour IOS et OSX, il y a quelques mois, j'ai trouvé une solution de contournement sur le SO.

<body onunload="">

OU via javascript

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

C'est un peu moche mais ça marche pendant un moment.

Je ne sais pas pourquoi, mais en renvoyant null à l' onunloadévénement, la page n'est pas mise en cache dans Safari.

Adriano Rosa
la source
0

Nous avons constaté que les iPhones et iPads plus anciens, exécutant les versions iOS 9 et 10, retournent parfois de faux résultats AJAX vides, peut-être en raison de la baisse de la vitesse du processeur d'Apple. Lors du retour du résultat vide, iOS n'appelle pas le serveur, comme s'il renvoyait un résultat du cache. La fréquence varie considérablement, d'environ 10% à 30% des appels AJAX retournant en blanc.

La solution est difficile à croire. Attendez 1 seconde et appelez à nouveau. Lors de nos tests, une seule répétition a suffi, mais nous avons écrit le code pour appeler jusqu'à 4 fois. Nous ne savons pas si l'attente 1s est requise, mais nous ne voulions pas risquer de surcharger notre serveur avec des rafales d'appels répétés.

Nous avons constaté que le problème était survenu avec deux appels AJAX différents, appelant des fichiers API différents avec des données différentes. Mais je crains que cela ne se produise sur n'importe quel appel AJAX. Nous ne le savons tout simplement pas, car nous n'inspectons pas tous les résultats AJAX et nous ne testons pas chaque appel plusieurs fois sur d'anciens appareils.

Les deux appels AJAX problématiques utilisaient: POST, asynchrone = true, setRequestHeader = ('Content-Type', 'application / x-www-form-urlencoded')

Lorsque le problème se produit, il n'y a généralement qu'un seul appel AJAX en cours. Ce n'est donc pas dû au chevauchement des appels AJAX. Parfois, le problème se produit lorsque l'appareil est occupé, mais parfois non, et sans DevTools, nous ne savons pas vraiment ce qui se passe à ce moment-là.

iOS 13 ne le fait pas, ni Chrome ni Firefox. Nous n'avons pas d'appareils de test fonctionnant sous iOS 11 ou 12. Peut-être que quelqu'un d'autre pourrait les tester?

Je note cela ici, car cette question est le meilleur résultat Google lors de la recherche de ce problème.

CaptureWiz
la source
-1

Cela n'a fonctionné avec ASP.NET qu'après avoir ajouté l'en- pragma:no-cachetête dans IIS . Cache-Control: no-cachen'était pas suffisant.

Boris
la source
-2

Je suggère une solution de contournement pour modifier la signature de la fonction pour qu'elle ressemble à ceci:

getNewRecordID (intRecordType, strTimestamp), puis passez également un paramètre TimeStamp également, et jetez simplement cette valeur du côté serveur. Cela fonctionne autour du problème.

fred1234
la source