自从升级到iOS 6以来,我们看到Safari的web视图可以自由缓存$。ajax调用。这是在一个PhoneGap应用程序的上下文中,所以它使用Safari WebView。我们的美元。ajax调用是POST方法,我们有缓存设置为false {cache:false},但这仍然发生。我们尝试手动添加一个时间戳到头部,但它没有帮助。

我们做了更多的研究,发现Safari只返回具有静态函数签名的web服务的缓存结果,并且在每次调用之间不会改变。例如,想象一个函数是这样的:

getNewRecordID(intRecordType)

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

苹果一定是急于让iOS 6运行得令人印象深刻,他们对缓存设置太满意了。有人在iOS 6上看到过这种行为吗?如果是的话,到底是什么原因造成的呢?


我们发现的解决方法是修改函数签名,像这样:

getNewRecordID(intRecordType, strTimestamp)

然后总是传递一个TimeStamp参数,并在服务器端丢弃这个值。这就解决了这个问题。


当前回答

GWT-RPC服务的一个快速解决方法是将其添加到所有远程方法中:

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

其他回答

我们发现,运行iOS 9和10版本的旧iphone和ipad偶尔会返回虚假的空白AJAX结果,可能是由于苹果降低了CPU速度。当返回空白结果时,iOS不调用服务器,就像从缓存中返回结果一样。频率差异很大,大约10%到30%的AJAX调用返回空白。

解决方案令人难以置信。请稍等片刻,然后再打来。在我们的测试中,只需要重复一次,但我们编写的代码最多可以调用4次。我们不确定是否需要1s等待,但我们不想冒着重复调用导致服务器负担过重的风险。

我们发现这个问题发生在两个不同的AJAX调用中,调用不同的API文件,使用不同的数据。但我担心在任何AJAX调用中都可能发生这种情况。我们只是不知道,因为我们没有检查每个AJAX结果,也没有在旧设备上多次测试每个调用。

这两个问题AJAX调用都使用:POST,异步= true, setRequestHeader = ('Content-Type', 'application/x-www-form-urlencoded')

当问题发生时,通常只有一个AJAX调用在进行。所以这不是由于重叠的AJAX调用。有时问题发生在设备忙的时候,但有时不是,没有DevTools,我们真的不知道当时发生了什么。

iOS 13没有这个功能,Chrome和Firefox也没有。我们没有任何运行iOS 11或12的测试设备。也许其他人可以测试一下?

我在这里注意到这一点是因为在搜索这个问题时,这个问题是谷歌的顶部结果。

经过一些调查,发现iOS6上的Safari会缓存没有cache - control头或者“cache - control: max-age=0”的post。

我所发现的防止这种缓存发生在全局级别而不是不得不在服务调用的末尾随机查询字符串的唯一方法是设置“Cache-Control: no-cache”。

So:

No cache - control或Expires headers = iOS6 Safari将缓存 cache - control max-age=0, immediate Expires = iOS6 Safari将缓存 cache - control: no-cache = iOS6 Safari将不缓存

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

此方法的响应是不可缓存的,除非响应 包括适当的Cache-Control或Expires报头字段。然而, 303(参见其他)响应可用于将用户代理定向到 检索可缓存资源。

所以理论上你可以缓存POST响应…谁知道。但直到现在,还没有其他浏览器制造商认为这是个好主意。但是,当没有设置Cache-Control或Expires头时,这并不考虑缓存,只有当有一些设置时。所以这一定是个漏洞。

下面是我在Apache配置的正确位中使用的东西,以针对整个API,因为它发生时,我实际上不想缓存任何东西,甚至是get。我不知道的是如何设置这只是POSTs。

Header set Cache-Control "no-cache"

更新:刚刚注意到,我没有指出,只有当POST是相同的,所以改变任何POST数据或URL,你是好的。你可以在其他地方添加一些随机数据到URL或一些POST数据。

更新:在Apache中,如果你想,你可以将“无缓存”限制为post:

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

我发现了一个变通办法,这让我很好奇为什么它能起作用。在阅读Tadej关于ASP的回答之前。NET web服务,我试图想出一些可行的方法。

我并不是说这是一个很好的解决方案,我只是想在这里记录一下。

主页:包括JavaScript函数checkStatus()。该方法调用另一个方法,该方法使用jQuery AJAX调用更新html内容。我使用setInterval调用checkStatus()。当然,我遇到了缓存问题。

解决方案:使用另一个页面调用更新。

在主页面上,我设置了一个布尔变量runUpdate,并在body标签中添加了以下内容:

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

在help .html中:

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

因此,如果从主页调用checkStatus(),我将获得缓存的内容。如果从子页调用checkStatus,就会得到更新的内容。

虽然添加缓存破坏者参数使请求看起来不同,这似乎是一个可靠的解决方案,但我不建议这样做,因为它会损害任何依赖于实际缓存发生的应用程序。使api输出为正确的头是可能的最佳解决方案,即使这比向调用者添加缓存破坏者稍微困难一些。

简单的解决方案,所有的web服务请求,假设你使用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()
    }));
});

点击这里阅读更多关于jQuery预过滤器调用的内容。

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