Safari sur iOS 6 cache $.des résultats ajax?

depuis la mise à niveau à iOS 6, Nous voyons Safari web view prendre la liberté de cacher les appels $.ajax . C'est dans le contexte D'une application PhoneGap qu'elle utilise le WebView Safari. Nos appels $.ajax sont des méthodes POST et nous avons mis le cache sur false {cache:false} , mais cela se produit toujours. Nous avons essayé d'ajouter manuellement un TimeStamp aux en-têtes, mais cela n'a pas aidé.

nous avons fait plus de recherche et avons constaté que Safari est seulement de retour résultats mis en cache pour les services web qui ont une signature de fonction qui est statique et ne change pas d'appel en 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 renvoie doivent être différentes à chaque fois.

doit être dans la hâte D'Apple de faire iOS 6 zip le long de façon impressionnante ils ont obtenu trop heureux avec les paramètres de cache. Quelqu'un d'autre a vu ce comportement sur iOS 6? Si oui, quelle est exactement la cause?


la solution trouvée était de modifier la fonction signature pour qu'elle ressemble à ceci:

getNewRecordID(intRecordType, strTimestamp)

et puis toujours passer dans un paramètre TimeStamp ainsi, et juste jeter cette valeur du côté du serveur. Cela fonctionne autour de la question. J'espère que cela aidera une autre pauvre âme qui passe 15 heures sur cette question comme je l'ai fait!

1036
demandé sur JakeGould 2012-09-20 10:07:23
la source

25 ответов

après un peu d'enquête, il s'avère que Safari sur iOS6 cache Les messages qui n'ont pas d'en-têtes Cache-Control ou même"Cache-Control: max-age=0".

le seul moyen que j'ai trouvé pour empêcher cette mise en cache de se produire au niveau mondial plutôt que d'avoir à pirater des interrogations aléatoires sur les appels de fin de service est de définir"Cache-Control: no-cache".

:

  • Pas de Cache-Control ou Expire headers = iOS6 Safari cache
  • Cache-Control max-age=0 et une expiration immédiate = iOS6 Safari cache
  • Cache-Control: no-cache = iOS6 Safari will NOT cache""

je soupçonne Qu'Apple tire avantage de cette spécification HTTP dans la section 9.5 à propos de POST:

les réponses à cette méthode ne sont pas identifiables, à moins que la réponse inclut le contrôle de Cache approprié ou de l'Expiration de champs d'en-tête. Cependant, la réponse 303 (voir autre) peut être utilisée pour diriger l'agent utilisateur vers récupérez une ressource détachable.

donc en théorie vous pouvez mettre en cache les réponses POST...qui savait. Mais aucun autre navigateur maker a jamais pensé que ce serait une bonne idée jusqu'à maintenant. Mais cela ne tient pas compte de la mise en cache quand aucun en-tête Cache-Control ou Expires N'est défini, seulement quand il y a un ensemble. Donc ça doit être un bug.

ci-dessous est ce que j'utilise dans le bon morceau de ma config Apache pour cibler l'ensemble de mon API parce qu'il se trouve que je ne veux pas vraiment mettre en cache quoi que ce soit, même Les gets. Ce que je ne sais pas, c'est comment mettre ça juste pour les messages.

Header set Cache-Control "no-cache"

mise à jour: je viens de remarquer que je n'ai pas fait remarquer que ce n'est que lorsque le POST est le MÊME, donc changer l'une des données du POST ou L'URL et vous êtes très bien. Donc vous pouvez comme mentionné ailleurs juste ajouter quelques données aléatoires à L'URL ou un peu de données POST.

mise à jour: vous pouvez limiter le "no-cache" juste aux messages si vous le souhaitez dans Apache:

SetEnvIf Request_Method "POST" IS_POST
Header set Cache-Control "no-cache" env=IS_POST
436
répondu Kieran 2012-09-24 11:26:32
la source

j'espère que cela peut être utile à d'autres développeurs frapper leur 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 cacher la réponse POST:

  • ajouter [cache-control: no-cache] dans les en-têtes de requête
  • ajout D'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 requêtes AJAX sont postées).

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

j'ajoute également l'en-tête [pragma: no-cache] à de nombreuses réponses de mon serveur.

si vous utilisez la solution ci-dessus soyez conscient que tout $.ajax () les appels que vous faites qui sont définis à global: false n'utiliseront pas les paramètres spécifiés dans $.ajaxSetup (), de sorte que vous aurez besoin d'ajouter les en-têtes de nouveau.

143
répondu Dave 2012-10-12 13:56:46
la source

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()
    }));
});

pour en savoir plus sur le jquery prefilter call ici .

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

64
répondu Baz1nga 2012-09-23 13:33:24
la source

j'ai eu le même problème avec une webapp obtenir des données de ASP.NET webservice

cela a fonctionné pour moi:

public WebService()
{
    HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    ...
}
40
répondu Tadej 2012-09-21 01:28:27
la source

je viens d'avoir ce problème aussi bien 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 ça. Il aurait été agréable d'Apple pour informer les développeurs de ce problème de mise en cache.

40
répondu Bashevis 2012-11-19 22:32:29
la source

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

In PHP :

header('cache-control: no-cache');
22
répondu goker.cebeci 2014-02-10 12:13:17
la source

de mon blog iOS 6.0 caching Ajax POST requests :

comment le corriger: il existe différentes méthodes pour empêcher la mise en cache des requêtes. La méthode recommandée est d'ajouter un en-tête no-cache. C'est comment il est fait.

jQuery:

Vérifiez iOS 6.0 et positionnez L'en-tête Ajax comme ceci:

$.ajaxSetup({ cache: false });

ZeptoJS:

Vérifiez iOS 6.0 et positionnez L'en-tête Ajax comme ceci:

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

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.
14
répondu kiranvj 2013-05-07 22:45:09
la source

Ce snippet JavaScript fonctionne très bien 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 il devrait aider.

7
répondu Jonathan 2013-01-26 02:11:59
la source

vous pouvez également corriger ce problème en modifiant la fonction jQuery Ajax en faisant ce qui suit (à partir du 1.7.1) en haut de la fonction Ajax (la fonction commence à la ligne 7212). Ce changement activera la fonctionnalité anti-cache intégrée de jQuery pour toutes les requêtes POST.

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

insérer sous la ligne 7221:

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

alors modifier ce qui suit (en commençant à 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, "_=" + 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, "_=" + ts);

    // If nothing was replaced, add timestamp to the end.
    s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
}
6
répondu Sam Shiles 2012-11-19 22:39:13
la source

une solution rapide pour les services GWT-RPC est d'ajouter ceci à toutes les méthodes distantes:

getThreadLocalResponse().setHeader("Cache-Control", "no-cache");
5
répondu Lars Høidahl 2012-10-17 02:57:52
la source

ceci est une mise à jour de la réponse de Baz1nga. Puisque options.data n'est pas un objet mais une chaîne de caractères, je viens de 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
répondu remcoder 2012-10-25 16:32:47
la source

afin de résoudre ce problème pour les WebApps ajouté à l'écran d'accueil, les deux top voté solutions doivent être suivies. La mise en cache doit être désactivée sur le serveur web pour éviter que de nouvelles requêtes ne soient mises en cache et des entrées aléatoires doivent être ajoutées à chaque requête post afin que les requêtes qui ont déjà été mises en cache puissent être traitées. Veuillez vous référer à mon post:

iOS6 existe - il un moyen pour effacer le cache ajax POST demandes de webapp ajouté à l'écran d'accueil?

AVERTISSEMENT: pour quelqu'un qui a mis en place une solution de contournement par l'ajout d'un timestamp à leurs demandes sans désactiver la mise en cache sur le serveur. Si votre application est ajoutée à l'écran d'accueil, chaque réponse post sera désormais mise en cache, le nettoyage du cache safari ne l'efface pas et ne semble pas expirer. A moins que quelqu'un ait un moyen de l'effacer, ça ressemble à une fuite de mémoire potentielle!

4
répondu fbader 2017-05-23 15:34:48
la source

C'est 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);    
3
répondu Spiff 2012-10-12 10:55:45
la source

Choses NE fonctionne PAS pour moi avec un iPad 4/iOS 6:

ma requête contenant: Cache-Control: no-cache

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

ajouter cache: false à mon appel ajax 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);
3
répondu Brian Ogden 2013-04-29 10:43:01
la source

ma solution dans ASP.NET (méthodes de pagination, service web, etc.)

protected void Application_BeginRequest(object sender, EventArgs e)
{
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
}
2
répondu Alexandre 2012-11-19 22:34:47
la source

bien que l'ajout de paramètres cache-buster pour rendre la requête différente semble être une solution solide, je conseillerais de ne pas le faire, car cela nuirait à toute application qui s'appuie sur la mise en cache réelle ayant lieu. Faire de la sortie APIs les en-têtes corrects est la meilleure solution possible, même si c'est un peu plus difficile que d'ajouter des Busters de cache aux appelants.

1
répondu Ivo Jansch 2012-09-24 11:39:33
la source

pour ceux qui utilisent Struts 1 , voici comment j'ai réglé 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.exemple.pavaner.filtrer.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() {
    }

}
1
répondu cbmeeks 2013-01-10 02:24:28
la source

j'ai pu résoudre mon problème en utilisant une combinaison de $.ajaxSetup et Ajouter un timestamp à l'url de mon post (pas aux paramètres/corps du post). 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');
                }
            }
        });
    });
});
1
répondu ShadeTreeDeveloper 2013-01-19 21:27:18
la source

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 beaucoup d'autres trucs pour éviter la mise en cache web, mais toujours penser 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 " hôtel qui utilise Squid ou d'autres produits de mise en cache.

si les utilisateurs utilisent proxy pour cacher sa position réelle, etc... le réel seul moyen d'éviter la mise en cache est l'horodatage dans la requête même si elle n'est pas utilisée.

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 dépôt de cache et aller télécharger à nouveau le contenu de la page.

1
répondu Lanello 2015-12-03 04:23:32
la source

en fonction de l'application, vous pouvez trouble shoot la question maintenant dans iOS 6 en utilisant Safari>Avancé>Web Inspector donc qui est utile avec cette situation.

connecter le téléphone à Safari sur un Mac et ensuite utiliser le menu développeur pour tirer sur l'application web.

Effacer les données du site web sur l'iPhone après mise à jour à iOS6, y compris spécifique à l'application en utilisant une vue Web. Une seule application avait un problème et cela l'a résolu pendant iOS6 Bêta Test retour, depuis lors, pas de réels problèmes.

vous pouvez avoir besoin de regarder votre application aussi bien, vérifiez NSURLCache si dans un 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 selon la vraie nature de votre problème, la mise en œuvre, etc. ..

Réf:$.les appels ajax

0
répondu Steven Strauss 2012-09-23 00:09:04
la source

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

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

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

Solution

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

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

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

Dans le de helper.html:

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

donc, si checkStatus() est appelé à partir de la page principale, j'obtiens le contenu caché. Si j'appelle checkStatus du page enfant, j'ai mis à jour le contenu.

0
répondu CM Kanode 2012-10-08 19:54:21
la source

pendant que mes pages de connexion et d'inscription fonctionne comme un charme dans Firefox, IE et Chrome... J'ai été aux prises avec ce problème dans Safari pour IOS et OSX, Il ya 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 retournant null à l'événement onunload la page ne se cache pas en Safari.

0
répondu Adriano Rosa 2014-07-20 01:12:36
la source

En Ruby Sinatra

before '*' do
  if env['REQUEST_METHOD'] == 'POST'
    headers 'Cache-Control' => 'no-cache, no-store, must-revalidate'
  end
end
0
répondu jchook 2015-03-02 08:12:56
la source

je suggère une solution de contournement pour modifier la signature de la fonction pour être quelque chose comme ceci:

getNewRecordID( intRecordType, strTimestamp) et puis toujours passer dans un paramètre TimeStamp aussi bien, et juste jeter cette valeur du côté du serveur. Cela fonctionne autour de la question.

0
répondu fred1234 2016-07-28 19:33:15
la source

ça a marché avec ASP.NET uniquement après l'ajout de l'en-tête pragma:no-cache dans IIS . Cache-Control: no-cache ne suffisait pas.

-1
répondu Boris 2012-11-19 22:35:35
la source

Autres questions sur javascript jquery ajax caching mobile-safari