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

JavaScript

神乐猿

2020-03-09

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

我们进行了更多研究,发现Safari仅返回具有静态功能签名且不会随调用而变化的Web服务的缓存结果。例如,假设有一个类似以下内容的函数:

getNewRecordID(intRecordType)

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

一定要赶紧Apple加快iOS 6的速度,他们对缓存设置太满意了。有人在iOS 6上看到过这种行为吗?如果是这样,到底是什么原因造成的?


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

getNewRecordID(intRecordType, strTimestamp)

然后也总是传入一个TimeStamp参数,只是在服务器端丢弃该值。这可以解决此问题。希望这对其他像我一样在这个问题上花费15个小时的可怜人有所帮助!

第389篇《iOS 6上的Safari是否缓存$ .ajax结果?》来自Winter(https://github.com/aiyld/aiyld.github.io)的站点

17个回答
西里前端Tom 2020.03.10

我建议一种变通办法将函数签名修改为如下形式:

getNewRecordID(intRecordType,strTimestamp),然后也总是传入一个TimeStamp参数,而只是在服务器端丢弃该值。这可以解决此问题。

西门阳光 2020.03.10

只有IIS中添加标头之后,才能ASP.NET一起使用还不够。pragma:no-cacheCache-Control: no-cache

神乐宝儿 2020.03.10

虽然我的登录页面和注册页面在Firefox,IE和Chrome中就像一个魅力一样……我一直在Safari的IOS和OSX上苦苦挣扎,几个月前,我在SO上找到了解决方法。

<body onunload="">

或通过javascript

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

这是一件丑陋的事情,但可以工作一段时间。

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

Tony阿飞 2020.03.10

我认为您已经解决了问题,但是让我分享有关Web缓存的想法。

的确,您可以在服务器端,客户端使用的每种语言添加许多标头,并且可以使用许多其他技巧来避免Web缓存,但始终认为您永远无法知道客户端从何处连接到服务器,您永远不会知道他是否正在使用使用Squid或其他缓存产品的酒店“热点”连接。

如果用户使用代理来隐藏其真实位置等,则避免缓存的唯一真正方法就是请求中的时间戳(如果未使用)。

例如:

/ajax_helper.php?ts=3211321456

然后,您必须传递的每个缓存管理器都没有在缓存存储库中找到相同的URL并重新下载页面内容。

GO蛋蛋 2020.03.10

我找到了一种解决方法,令我对其工作原理感到好奇。在阅读Tadej有关ASP.NET Web服务的答案之前,我试图提出一些可行的方法。

我并不是说这是一个很好的解决方案,但我只是想在此处进行记录。

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

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

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

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

在helper.html中:

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

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

JinJinEva 2020.03.10

根据应用程序的不同,您现在可以使用Safari>高级> Web检查器在iOS 6中解决问题,因此在这种情况下很有帮助。

将手机连接到Mac上的Safari,然后使用开发人员菜单对网络应用进行故障排除。

更新到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电话

NearItachi 2020.03.10

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

西门十三LEY 2020.03.10

对于那些使用的人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() {
    }

}
Harry飞云 2020.03.10

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

iOS6-是否有办法清除添加到主屏幕的Web应用程序的缓存Ajax POST请求?

警告:对于通过在请求中添加时间戳而不关闭服务器上的缓存来实施变通方法的任何人。如果您的应用程序已添加到主屏幕,则现在将缓存每个帖子响应,清除Safari缓存不会清除它,并且它似乎也不会过期。除非有人有办法清除它,否则这似乎是潜在的内存泄漏!

Harry小胖古一 2020.03.10

这就是GWT-RPC的解决方法

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);    
古一村村Gil 2020.03.10

我在ASP.NET中的解决方法(页面方法,Web服务等)

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

这是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();
  }
});
逆天Jim 2020.03.10

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

getThreadLocalResponse().setHeader("Cache-Control", "no-cache");
樱理查德 2020.03.10

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

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

所以:

  • 没有Cache-Control或Expires标头= iOS6 Safari将缓存
  • 缓存控制max-age = 0,并且立即到期= iOS6 Safari将会缓存
  • 缓存控制:无缓存= iOS6 Safari无法缓存

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

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

因此,从理论上讲,您可以缓存POST响应...谁知道。但是到目前为止,没有其他浏览器制造商曾认为这是一个好主意。但这仅在设置了Cache-Control或Expires头时才考虑缓存。因此,它一定是一个错误。

以下是我在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
Tom西里 2020.03.10

假设您使用的是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 prefilter调用的更多信息

如果您不使用jQuery,请检查文档以查找您选择的库。它们可能具有类似的功能。

Davaid古一 2020.03.10

我从web应用程序从ASP.NET Web服务获取数据时遇到了同样的问题

这为我工作:

public WebService()
{
    HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    ...
}
Davaid飞羽 2020.03.10

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

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

我浪费了几个小时弄清楚这个问题。Apple最好将这个缓存问题通知开发人员。

问题类别

JavaScript Ckeditor Python Webpack TypeScript Vue.js React.js ExpressJS KoaJS CSS Node.js HTML Django 单元测试 PHP Asp.net jQuery Bootstrap IOS Android