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

Javascript iOS 6上的Safari是否缓存$.ajax结果?,javascript,jquery,ajax,caching,mobile-safari,Javascript,Jquery,Ajax,Caching,Mobile Safari,自从升级到iOS 6后,我们看到Safari的web视图可以随意缓存$.ajax调用。这是在PhoneGap应用程序的上下文中,因此它使用Safari WebView。我们的$.ajax调用是POST方法,我们将cache设置为false{cache:false},但这仍然在发生。我们尝试手动将时间戳添加到标题中,但没有任何帮助 我们做了更多的研究,发现Safari只返回具有静态函数签名的web服务的缓存结果,并且不会随调用而改变。例如,想象一个名为以下内容的函数: getNewRecordID

自从升级到iOS 6后,我们看到Safari的web视图可以随意缓存
$.ajax
调用。这是在PhoneGap应用程序的上下文中,因此它使用Safari WebView。我们的
$.ajax
调用是
POST
方法,我们将cache设置为false
{cache:false}
,但这仍然在发生。我们尝试手动将
时间戳添加到标题中,但没有任何帮助

我们做了更多的研究,发现Safari只返回具有静态函数签名的web服务的缓存结果,并且不会随调用而改变。例如,想象一个名为以下内容的函数:

getNewRecordID(intRecordType)
此函数一次又一次地接收相同的输入参数,但每次返回的数据应该不同

一定是苹果急于让iOS 6快速运行,他们对缓存设置太满意了。还有人在iOS 6上见过这种行为吗?如果是,究竟是什么原因造成的


我们发现的解决方法是将函数签名修改为如下内容:

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

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

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

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

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

经过一番调查,发现iOS6上的Safari会缓存没有缓存控制头甚至“缓存控制:最大年龄=0”的帖子

我发现防止这种缓存在全局级别发生的唯一方法是设置“缓存控制:无缓存”,而不必对服务结束调用进行随机查询

因此:

  • 无缓存控制或Expires headers=iOS6 Safari将缓存
  • 缓存控制最大年龄=0,立即过期时间=iOS6 Safari将缓存
  • 缓存控制:无缓存=iOS6 Safari将不缓存
我怀疑苹果是在利用第9.5节关于POST的HTTP规范中的这一点:

对此方法的响应不可缓存,除非响应 包括适当的缓存控制或Expires标头字段。然而, 303(参见其他)响应可用于指示用户代理 检索可缓存的资源

所以理论上你可以缓存帖子回复…谁知道呢。但迄今为止,没有其他浏览器制造商认为这是一个好主意。但是,当没有设置缓存控制或Expires头时,这并不能解释缓存,只有当设置了一些缓存控制或Expires头时。所以它一定是一只虫子

下面是我在Apache配置的正确部分中使用的内容,以我的整个API为目标,因为实际上我不想缓存任何东西,甚至不想缓存数据。我不知道的是如何为帖子设置这个

Header set Cache-Control "no-cache"
更新:只是注意到我没有指出只有当帖子是相同的,所以更改任何帖子数据或URL,你就没事了。因此,您可以像其他地方提到的那样,向URL添加一些随机数据或一点POST数据

更新:如果您希望在Apache中这样做,可以将“无缓存”限制为仅发布:

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

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

这对我很有用:

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

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

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

将手机连接到Mac上的Safari,然后使用开发者菜单对web应用进行故障排除

更新到iOS6后,清除iPhone上的网站数据,包括特定于使用Web视图的应用程序的数据。只有一个应用程序有问题,这在IOS6测试期间解决了问题,从那时起就没有真正的问题

您可能还需要查看您的应用程序,如果在自定义应用程序的WebView中,请查看NSURLCache

我想这取决于你的问题的真实性质,实施情况等等


Ref:$.ajax调用

最后,我找到了一个解决上传问题的方法

在JavaScript中:

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


虽然添加cache buster参数以使请求看起来不同似乎是一个可靠的解决方案,但我建议不要这样做,因为这会损害任何依赖实际缓存的应用程序。使API输出正确的头是最好的解决方案,即使这比向调用者添加缓存清除器稍微困难。

我在(pagemethods、webservice等)中的解决方法


只有在中添加了
pragma:no cache
头之后,它才能使用<代码>缓存控制:没有缓存是不够的。

您还可以通过在Ajax函数顶部执行以下操作(从1.7.1开始)(函数从第7212行开始)来修改函数来解决此问题。此更改将为所有POST请求激活jQuery的内置反缓存功能

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

在第7221行下方插入:

if (options.type === "POST") {
    options.cache = false;
}
然后修改以下内容(从第7497行开始)

致:


为了解决添加到主屏幕的WebApps的此问题,需要遵循两种最受欢迎的解决方法。需要关闭Web服务器上的缓存,以防止新请求被缓存,并且需要向每个post请求添加一些随机输入,以便已缓存的请求能够通过。请参阅我的帖子:

警告:任何实施
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 : "");
}
<iframe src="helper.html" style="display: none; visibility: hidden;"></iframe>
<meta http-equiv="refresh" content="5">
<script type="text/javascript">
    if (parent.runUpdate) { parent.checkStatus(); }
</script>
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);    
$.ajaxSetup({
    type: 'POST',
    headers: { "cache-control": "no-cache" }
});
getThreadLocalResponse().setHeader("Cache-Control", "no-cache");
$.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();
  }
});
$.ajaxSetup({ cache: false });
$.ajax({
    type: 'POST',
    headers : { "cache-control": "no-cache" },
    url : ,
    data:,
    dataType : 'json',
    success : function(responseText) {…}
httpResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
Response.Cache.SetNoStore();
Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);
header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1.
header('Pragma: no-cache'); // HTTP 1.0.
<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>
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() {
    }

}
$(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');
                }
            }
        });
    });
});
$.ajaxSetup({
    cache: false,
    headers: {
        'Cache-Control': 'no-cache'
    }
});
//asp.net's:
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache)
 $.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);
/ajax_helper.php?ts=3211321456
<body onunload="">
<script type="text/javascript">
window.onunload = function(e){
    e.preventDefault();
    return;
};
</script>