iOS 6 上的 Safari 是否缓存 $.ajax 结果?

IT技术 javascript jquery ajax caching mobile-safari
2021-02-03 11:31:34

自从升级到 iOS 6 以来,我们看到 Safari 的 web 视图冒昧地缓存$.ajax调用。这是在 PhoneGap 应用程序的上下文中,因此它使用的是 Safari WebView。我们的$.ajax调用是POST方法,我们将缓存设置为 false {cache:false},但这种情况仍在发生。我们尝试手动将 a 添加TimeStamp到标题中,但没有帮助。

我们进行了更多研究,发现 Safari 仅返回具有静态函数签名且不会随调用而变化的 Web 服务的缓存结果。例如,想象一个名为的函数,如下所示:

getNewRecordID(intRecordType)

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

肯定是苹果急于推出 iOS 6,他们对缓存设置太满意了。有没有其他人在 iOS 6 上看到过这种行为?如果是这样,究竟是什么原因造成的?


我们找到的解决方法是将函数签名修改为如下所示:

getNewRecordID(intRecordType, strTimestamp)

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

6个回答

经过一番调查,结果表明 iOS6 上的 Safari 会缓存没有 Cache-Control 标头甚至“Cache-Control: max-age=0”的 POST。

我发现阻止这种缓存在全局级别发生而不是必须在服务调用结束时破解随机查询字符串的唯一方法是设置“缓存控制:无缓存”。

所以:

  • 无 Cache-Control 或 Expires 标头 = iOS6 Safari 将缓存
  • Cache-Control max-age=0 并且立即过期 = iOS6 Safari 将缓存
  • 缓存控制:no-cache = iOS6 Safari 不会缓存

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

对此方法的响应不可缓存,除非响应包含适当的 Cache-Control 或 Expires 标头字段。但是,303(参见其他)响应可用于指示用户代理检索可缓存资源。

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

下面是我在我的 Apache 配置的正确位中使用的内容来定位我的整个 API,因为碰巧我实际上并不想缓存任何东西,甚至是获取。我不知道如何仅为 POST 设置它。

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
我看到了 Apple 的发展方向,但我们看到了对 POST 请求的缓存响应,即使我们的响应不包含任何 Cache-Control 或 Expires 标头。这个实例 iOS6 不应该缓存和发送每个请求。这不会发生。
2021-03-17 11:31:34
有谁知道结果在设备上缓存了多长时间?我试过杀死 safari 并重新启动我的手机,但它仍然被缓存。我知道它适用于清除浏览器缓存,但我想知道曾经遇到问题的用户需要多长时间才能消失。不是每个人都会想到清除他们的缓存......
2021-03-18 11:31:34
您引用的 HTTP 规范的一部分并不能证明 iOS 6 的缓存行为是正确的。默认行为应该是不缓存 POST 响应(即未定义“Cache-Control”标头时)。该行为违反了规范,应被视为错误。任何构建 xml/json api web 服务的人都应该用“缓存控制:无缓存”来装饰他们的 POST 响应来解决这个问题。
2021-03-19 11:31:34
POST 请求是非幂等的,这意味着它们不应被缓存,除非响应通过其响应头明确建议这样做。
2021-03-26 11:31:34
正如大卫所说,这明显违反了你引用的句子。如果没有“Cache-Control 或 Expires 标头字段”,则显然不包括适当的此类标头。然而,您自己的调查表明它在这种情况下缓存。请编辑您的答案。
2021-04-01 11:31:34

我希望这对其他开发人员在这个问题上撞墙有用。我发现以下任何一种情况都会阻止 iOS 6 上的 Safari 缓存 POST 响应:

  • 在请求头中添加 [cache-control: no-cache]
  • 添加一个可变的 URL 参数,例如当前时间
  • 在响应头中添加 [pragma: no-cache]
  • 在响应头中添加 [cache-control: no-cache]

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

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

我还将 [pragma: no-cache] 标头添加到我的许多服务器响应中。

如果您使用上述解决方案,请注意您进行的任何 $.ajax() 调用都设置为 global: false 将不会使用 $.ajaxSetup() 中指定的设置,因此您需要再次添加标头。

我也认为这是最好的方法,而不是带有附加参数的解决方法。我们只在需要它的调用中添加了它,对于总是具有相同返回值的调用,缓存对最终用户来说可能是一件好事。
2021-03-31 11:31:34
完美运行 - 您还可以将作为参数添加到请求中 $.ajax({type: 'POST', headers: { 'cache-control': 'no-cache' }, etc.})
2021-04-02 11:31:34
什么是 [pragma: no-cache]?pragma 键的用途是什么?
2021-04-04 11:31:34
这对我有用,但我不明白如何。我已经在我的 ajaxSetup 中指定了 cache: false ,并查看请求标头,归结为 Cache-Control: no-cache 和 Pragma: no-cache - 但它仍然会缓存在 iPad 上。然后,当我将 headers: { "cache-control": "no-cache" } 添加到 ajaxSetup 中时,它会将 Cache-Control 标头加倍为“no-cache, no-cache” - 并停止缓存。这里发生了什么事?
2021-04-06 11:31:34
这是该错误的正确解决方案。错误在于 iOS 6 将从它的缓存中处理 POST 请求,而不是将它们发送到服务器。错误不在于它缓存来自 POST 请求的响应(这是允许的)。如果您仍希望对从缓存中检索的 POST 请求做出响应,以便对该 URI 的后续 GET 请求,请使用此解决方案。
2021-04-08 11:31:34

假设您使用的是 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,请查看您选择的库的文档。它们可能具有相似的功能。

$.ajax({ "cache": false ...}) 呢?它会在附加 _=[TIMESTAMP] 时起作用吗?(我没有这样的设备来测试它)
2021-03-27 11:31:34
我已经发布了 Karussell 提出的解决方案的完整实现。请看我下面的回答。
2021-03-27 11:31:34
它对我不起作用,服务器响应:“无效的原始 JSON:timeStamp” asp.net / iis 7.5
2021-03-28 11:31:34
这不起作用。它不合并帖子参数。Dave 的帖子是一个更好的解决方案。
2021-03-28 11:31:34
@卡鲁塞尔。刚刚尝试设置 $.ajax({ "cache": false ...})。这不能解决 iOS6 上 POST 请求的问题。大概是因为 JQuery 根据他们的文档假设没有浏览器足够愚蠢来缓存发布请求。“使用 POST 获取的页面永远不会被缓存,因此 jQuery.ajaxSetup() 中的缓存和 ifModified 选项对这些请求没有影响。”
2021-04-02 11:31:34

我刚刚在PhoneGap应用程序中也遇到了这个问题我通过getTime()以下方式使用 JavaScript 函数解决了它

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

我浪费了几个小时来弄清楚这一点。苹果公司最好通知开发人员这个缓存问题。

我花了将近 5 个小时来解决这个问题,最后添加时间戳就可以了function send_ajax(my_data,refresh) .. 参考这里stackoverflow.com/questions/14733772/...
2021-03-12 11:31:34
我打算评论 using{cache:false}作为$.post()or的选项$.ajaxSetup(),但根据文档,这些参数被忽略;jQuery 将“从不缓存”发布请求,但不会考虑浏览器。也许更简洁的选择是使用$.ajaxPrefilter().
2021-03-31 11:31:34

我在 webapp 从 ASP.NET webservice 获取数据时遇到了同样的问题

这对我有用:

public WebService()
{
    HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    ...
}
请!!!!设置一个条件,仅在 IOS 6 上应用此功能,内容缓存对任何应用程序都至关重要。
2021-03-21 11:31:34
在 iOS6 上不起作用,请参阅我在线程末尾的答案
2021-03-28 11:31:34
非常感谢你!我疯狂地想弄清楚为什么 iPhone 的表现与其他所有平台都如此不同。这个 ASP.NET 特定的解决方案为我节省了大量时间。
2021-03-30 11:31:34