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

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

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

getNewRecordID(intRecordType)

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

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


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

getNewRecordID(intRecordType, strTimestamp)

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

144214 次浏览

我在一个PhoneGap应用程序中也遇到了这个问题。我用JavaScript函数getTime()解决了这个问题,如下所示:

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

我花了几个小时才想明白。如果苹果能通知开发者这个缓存问题就好了。

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

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

所以:

  • 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规范中利用了这一点:

对这个方法的响应是不可缓存的,除非response包括适当的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_POSTHeader set Cache-Control "no-cache" env=IS_POST

我有同样的问题,一个web应用程序从ASP获取数据。网网络服务

这招对我很管用:

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

简单的解决方案,所有的web服务请求,假设你使用jQuery:

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {// you can use originalOptions.type || options.type to restrict specific type of requestsoptions.data = jQuery.param($.extend(originalOptions.data||{}, {timeStamp: new Date().getTime()}));});

阅读更多关于jQuery预过滤器调用在这里

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

根据应用程序的不同,你可以在iOS 6中使用Safari>Advanced>Web Inspector来解决这个问题,所以这对这种情况很有帮助。

将手机连接到Mac电脑上的Safari浏览器,然后使用开发人员菜单来解决web应用程序的问题。

在更新到iOS6后,清除iPhone上的网站数据,包括使用Web View的特定应用程序。只有一个应用程序有问题,这解决了它在IOS6 Beta测试的方式,从那以后没有真正的问题。

你可能也需要看看你的应用,如果在自定义应用的WebView中,检查NSURLCache。

https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSURLCache_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003754

我想这取决于你的问题的真正性质,实现等等。

裁判:美元。ajax调用

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

在JavaScript中:

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

在# 0:

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

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

我在ASP。网中的解决方法(pagemethods, webservice等)

protected void Application_BeginRequest(object sender, EventArgs e){Response.Cache.SetCacheability(HttpCacheability.NoCache);}

只有在IIS中添加pragma:no-cache头后,它才能与ASP。网一起工作。第一条是不够的。

您还可以修改这个问题,方法是在Ajax函数的顶部执行以下操作(从1.7.1开始)(函数从第7212行开始),从而修改jQuery Ajax函数。此更改将激活jQuery内置的反缓存功能,用于所有POST请求。

(完整的脚本可以在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 URLif (s.data) {s.url += (rquery.test(s.url) ? "&" : "?") + s.data;// #9682: remove data so that it's not used in an eventual retrydelete s.data;}
// Get ifModifiedKey before adding the anti-cache parameterifModifiedKey = s.url;
// Add anti-cache in URL if neededif (s.cache === false) {var ts = jQuery.now(),// Try replacing _= if it is thereret = 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 contentif (!s.hasContent) {// If data is available, append data to URLif (s.data) {s.url += (rquery.test(s.url) ? "&" : "?") + s.data;// #9682: remove data so that it's not used in an eventual retrydelete s.data;}
// Get ifModifiedKey before adding the anti-cache parameterifModifiedKey = s.url;}
// Add anti-cache in URL if neededif (s.cache === false) {var ts = jQuery.now(),// Try replacing _= if it is thereret = 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 : "");}

为了解决添加到主屏幕的WebApps的这个问题,需要遵循投票最多的两个解决方案。需要在web服务器上关闭缓存,以防止新的请求继续缓存,并且需要在每个post请求中添加一些随机输入,以便已经缓存的请求能够通过。请参考我的帖子:

iOS6 -有一种方法来清除缓存的ajax POST请求webapp添加到主屏幕?< / >

警告:给那些通过在请求中添加时间戳而没有关闭服务器缓存来实现解决方案的人。如果你的应用被添加到主屏幕,每一个帖子的响应现在都将被缓存,清除safari缓存不会清除它,它似乎不会过期。除非有人有办法清除它,否则这看起来像一个潜在的内存泄漏!

我发现了一个变通办法,这让我很好奇为什么它能起作用。在阅读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,就会得到更新的内容。

这就是GWT-RPC的工作

class AuthenticatingRequestBuilder extends RpcRequestBuilder{@Overrideprotected 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);

我希望这能对其他在这个问题上绞尽脑汁的开发人员有所帮助。我发现以下任何一个阻止Safari在iOS 6上缓存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]标头。

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

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

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

这是Baz1nga对答案的更新。因为options.data不是一个对象,而是一个字符串,我只是诉诸于连接时间戳:

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {if (originalOptions.type == "post" || options.type == "post") {
if (options.data && options.data.length)options.data += "&";elseoptions.data = "";
options.data += "timeStamp=" + new Date().getTime();}});

我在自己的博客iOS 6.0 caching Ajax POST requests中写道:

如何修复:有多种方法可以防止缓存请求。推荐的方法是添加一个无缓存头。事情是这样的。

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.

对于那些使用Struts 1的人,下面是我解决这个问题的方法。

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.example.struts.filters.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() {}
}

我能够通过使用$的组合来解决我的问题。ajaxSetup和追加一个时间戳到我的帖子的url(不是post参数/体)。这是基于之前回答的建议

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

这个JavaScript代码片段与jQuery和jQuery Mobile一起工作:

$.ajaxSetup({cache: false,headers: {'Cache-Control': 'no-cache'}});

只需将它放在JavaScript代码中的某个地方(在加载jQuery之后,最好在执行AJAX请求之前),它就会有帮助。

对于我来说,使用iPad 4/iOS 6时我排在第0位的事情:

我的请求包含:Cache-Control:no-cache

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

添加缓存:false到我的jQuery ajax调用

 $.ajax({url: postUrl,type: "POST",cache: false,...

只有这招管用:

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

我认为你已经解决了你的问题,但是让我分享一个关于web缓存的想法。

确实,你可以在你使用的每种语言中添加许多头文件,服务器端,客户端,你可以使用许多其他技巧来避免web缓存,但总是认为你永远不知道客户端从哪里连接到你的服务器,你永远不知道他是否使用酒店的“热点”连接,使用Squid或其他缓存产品。

如果用户使用代理来隐藏他的真实位置,等等,真正的是避免缓存的唯一方法是请求中的时间戳,如果没有使用。

例如:

/ajax_helper.php?ts=3211321456

然后每个缓存管理器你必须通过没有找到相同的URL在缓存库和去重新下载页面内容。

虽然我的登录和注册页面在Firefox, IE和Chrome中工作得很有魅力……我在IOS和OSX的Safari中一直在努力解决这个问题,几个月前我在SO上找到了一个解决方案。

<body onunload="">

或通过javascript

<script type="text/javascript">window.onunload = function(e){e.preventDefault();return;};</script>

这是有点丑陋的事情,但有效的一段时间。

我不知道为什么,但是返回null到onunload事件页面不会被缓存在Safari中。

我建议将函数签名修改成这样:

< p > getNewRecordID (intRecordType strTimestamp)然后总是传递一个TimeStamp参数,并在服务器端丢弃这个值。

我们发现,运行iOS 9 &10、偶尔返回虚假的空白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的测试设备。也许其他人可以测试一下?

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