Question Safari sur iOS 6 cache-t-il les résultats $ .ajax?


Depuis la mise à niveau vers iOS 6, nous voyons la vue Web de Safari prendre la liberté de la mise en cache $.ajax appels. C'est dans le contexte d'une application PhoneGap donc il utilise Safari WebView. Notre $.ajax les appels sont POST méthodes et nous avons mis en cache à faux {cache:false}, mais cela arrive encore. Nous avons essayé d'ajouter manuellement un TimeStamp aux en-têtes mais cela n'a pas aidé.

Nous avons fait plus de recherches et constaté que Safari ne restitue que les résultats mis en cache pour les services Web qui ont une signature de fonction statique et qui ne change pas d'appel à appel. 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 retourne doivent être différentes à chaque fois.

Doit être dans la hâte d'Apple pour faire iOS 6 zip le long impressionnant, ils sont devenus trop heureux avec les paramètres de cache. Est-ce que quelqu'un d'autre a vu ce comportement sur iOS 6? Si oui, qu'est-ce qui le cause exactement?


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 dans un TimeStamp paramètre aussi, et juste jeter cette valeur sur le 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 je l'ai fait!


1029
2017-09-20 06:07


origine


Réponses:


Après un peu d'enquête, il s'avère que Safari sur iOS6 cache les POST qui n'ont pas d'en-têtes 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".

Alors:

  • Aucun cache-contrôle ou expires en-têtes = iOS6 Safari sera mis en cache
  • Cache-Control max-age = 0 et un Expires immédiat = iOS6 Safari sera mis en cache
  • Cache-Control: no-cache = iOS6 Safari ne cache PAS

Je soupçonne que Apple en profite 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 les champs d'en-tête Cache-Control ou Expires appropriés. cependant,      la réponse 303 (Voir autre) peut être utilisée pour diriger l'agent utilisateur vers      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 navigateurs 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 lorsque aucun en-tête Cache-Control ou Expires n'est défini, uniquement lorsqu'il existe un ensemble. Donc ça doit être un bug.

Voici ce que j'utilise dans le bon morceau de ma configuration Apache pour cibler l'ensemble de mon API car, en fait, je ne veux pas vraiment mettre en cache quoi que ce soit. Ce que je ne sais pas, c'est comment régler ceci juste pour les POSTES.

Header set Cache-Control "no-cache"

Mise à jour: J'ai juste remarqué que je n'ai pas précisé que c'est seulement quand le POST est le même, donc changez n'importe quelle donnée de POST ou URL et tout va bien. Ainsi, comme mentionné précédemment, ajoutez simplement des données aléatoires à l'URL ou un peu de données POST.

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

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

434
2017-09-20 16:06



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

  • ajouter [cache-control: no-cache] dans les en-têtes de la requête
  • ajouter un paramètre d'URL variable tel que l'heure actuelle
  • ajouter [pragma: no-cache] dans les en-têtes de réponse
  • ajouter [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 serveur.

Si vous utilisez la solution ci-dessus, sachez que tous les appels $ .ajax () que vous faites sont globaux: false n'utilisera PAS les paramètres spécifiés dans $ .ajaxSetup (), vous devrez donc rajouter les en-têtes.


143
2017-10-12 09:56



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 de préfiltre jQuery ici.

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


64
2017-09-21 08:53



J'ai eu le même problème avec une webapp obtenir des données à partir du service web ASP.NET

Cela a fonctionné pour moi:

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

40
2017-09-20 21:28



Je viens d'avoir cette question dans un PhoneGap application. 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. Cela aurait été bien d'Apple d'avertir les développeurs de ce problème de mise en cache.


40
2017-09-20 07:34



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

Dans PHP:

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

22
2017-09-22 10:16



De mon propre blog iOS 6.0 mise en cache des demandes Ajax POST:

Comment le résoudre: 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. C'est comme ça que c'est 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 que les données ne soient envoyé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.

14
2017-11-14 06:02



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 que jQuery est chargé, et mieux avant de faire des requêtes AJAX) et cela devrait aider.


7
2018-01-25 22:11



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

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

5
2017-10-16 22:57



Ceci est une mise à jour de la réponse de Baz1nga. Depuis options.data n'est pas un objet mais une chaîne que j'ai juste recouru pour concaténer 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();
  }
});

5
2017-10-25 12:32