javascript - Safari在iOS 6缓存$.ajax结果?

  显示原文与译文双语对照的内容

自从升级到 iOS 6之后,我们看到safari视图的站点可以自由缓存 $.ajax 调用。 这是在PhoneGap应用程序的上下文中,所以它使用 Safari web view 。 我们的$.ajax 调用是 POST 方法,并且缓存设置为假 {cache:false},但这仍然是发生的。 我们试图手动添加一个 TimeStamp 到头部,但它没有帮助。

我们做了更多的研究,发现Safari只返回 Web服务的缓存结果,它有一个静态的函数签名,它是静态的,并且不会从调用改变。 例如假设一个函数类似于:


getNewRecordID(intRecordType)

这里函数一次又一次接收相同的输入参数,但每次返回的数据都应该是不同的。

苹果必须急于让 iOS 6压缩,他们对缓存设置感到太满意了。 是否有人在 iOS 6上看到这种行为? 如果是的话,到底是什么导致了它?


我们发现的解决办法是将函数签名修改为如下所示:


getNewRecordID(intRecordType, strTimestamp)

然后总是传入一个 TimeStamp 参数,并在服务器端丢弃该值。 这可以解决这个问题。 我希望这有助于其他一些在这个问题上花费 15小时的可怜的灵魂 !

时间:

经过一番调查,在iOS6上,就证明了,Safari会缓存文章能包含选择任何 Cache-Control header,或者甚至"Cache-Control: max-age=0"。

防止这种缓存情况的发生在世界级的唯一我发现的方法,而无需在 hack 随机querystrings拖到结束的服务电话是设置"cache-control: no-cache"。

所以:

  • 没有Cache-Control或者过期头= iOS6 Safari将缓存
  • Cache-Control max-age=0和一个立即过期= iOS6 Safari将缓存
  • Cache-Control: no-cache = iOS6 Safari将不会缓存

我怀疑苹果在第 9.5节的HTTP规范中利用了这一点:

对此方法的响应不可缓存,除非响应包含适当的Cache-Control或者过期标头字段。 但是,303 ( 查看其他) 响应可以用于指导 User Agent 检索可以缓存的资源。

所以在理论上你可以缓存POST响应。。谁知道。 但没有其他浏览器制造商认为这将是一个好主意,直到现在。 但这并没有Cache-Control或者到期时无法考虑的缓存的头被重置时,仅当有一些设置。 所以它必须是一个 Bug 。

下面是什么是我在正确的位的数据 Apache config实际上整个我的API为目标,因为碰巧我不希望缓存任何内容,甚至获取。 我不知道的是如何为帖子设置这个。


Header set Cache-Control"no-cache"

更新:刚刚注意到,我没有指出,它只有当那些帖子是相同的,所以更改任何数据或者网址以及你对文章的状态很好 所以你可以在别处随意添加一些随机数据到URL或者一些POST数据中。

更新:如果你希望在Apache中这样做的话,你可以限制"no-cache"的发布:


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

在这里one,我希望这可以用于做其他开发人员翻动它的头部对照墙壁上, 我发现以下任何一个阻止 iOS 6上的Safari缓存POST响应:

  • 在请求标头中添加[ cache-control: no-cache]
  • 添加变量URL参数,如当前时间
  • 添加[ 杂注:响应标头中的no-cache]
  • 在响应标头中添加[ cache-control: no-cache]

我的解决方案在我的Javascript ( 我所有的AJAX请求都是 POST ) 中如下。


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

我还添加了[ 杂注: no-cache]标头到许多服务器响应。

如果你使用上述解决方案,请注意你所做的任何 $.ajax() 调用都设置为全局的: false将不使用在 $.ajaxSetup(), 中指定的设置,因此需要重新添加标题。

假设你使用的是 jQuery,那么可以简单地解决所有web服务请求:


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

阅读更多关于jQuery预过滤器调用的信息。

如果你没有使用 jQuery,请检查你的选择库的文档。 它们可能有相似的功能。

从 ASP.NET web service获取数据时,我遇到了同样的问题

我这里可以工作:


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

我在 PhoneGap的应用程序中也有这个问题。 我用以下方式使用JavaScript函数 getTime() 解决了它:


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

我花了几个小时才算出来。 苹果向开发者通知这个缓存问题会很好。

最后,我有一个解决上传问题的解决方案。

在JavaScript中:


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

PHP 中:


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

从我自己的博客文章 6.0缓存 Ajax POST请求:

如何解决它:有多种方法可以防止请求缓存。 推荐的方法是添加一个no-cache头。 这就是完成的方式。

jQuery:

检查 iOS 6.0并设置如下所示的Ajax标头:


$.ajaxSetup({ cache: false });

ZeptoJS:

检查 iOS 6.0并设置如下所示的Ajax标头:


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

服务器端服务器

Java:


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

请确保在页面顶部添加这里在将任何数据发送回客户端。

.NET


Response.Cache.SetNoStore();

或者


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.

这是baz1nga的一个更新。 因为 options.data 不是一个对象,而是一个字符串,我只是用来连接时间戳:


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

你也可以解决这个问题通过修改 jQueryAjax 函数通过执行下列操作来( 从 1.7.1开始) 到Ajax函数( 函数从第 7212行开始)的顶部。 这里更改将激活所有POST请求的jQuery内置的anti-cache特性。

( 完整脚本可以在 http://dl.dropbox.com/u/58016866/jquery-1.7.1.js . )

在第 7221行插入:


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

然后修改以下( 从 ~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 :"");
}

...