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

2020/09/18 16:31 · javascript ·  · 0评论

自从升级到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参数,只是在服务器端丢弃该值。这可以解决此问题。我希望这对其他像我一样在这个问题上花费15个小时的可怜人有所帮助!

经过一番调查,结果发现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

我希望这对其他开发人员将头撞到墙上的东西有用。我发现以下任何一项都会阻止iOS 6上的Safari缓存POST响应:

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

我的解决方案如下所示(我的所​​有AJAX请求均为POST)。

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

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

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

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

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

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

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

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

这对我有用:

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

最后,我有一个解决上传问题的方法。

在JavaScript中:

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

PHP中

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

从我自己的博客文章iOS 6.0中缓存Ajax POST请求

修复方法:有多种方法可以防止缓存请求。推荐的方法是添加一个非缓存头。这是完成的方式。

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");

在将任何数据发送到客户端之前,请确保将其添加到页面顶部。

。净

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.

这个JavaScript片段适用于jQuery和jQuery Mobile:

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

只需将其放在JavaScript代码中的某个位置(加载jQuery之后,最好在执行AJAX请求之前),它应该会有所帮助。

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

(完整的脚本位于)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 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 : "");
}

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 += "&";
    else
      options.data = "";

    options.data += "timeStamp=" + new Date().getTime();
  }
});

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

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

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

使用iPad 4 / iOS 6对我不起作用的事情

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

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

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

 $.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);

这就是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);    

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

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

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

对于那些使用的人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并将时间戳添加到我的帖子的网址(而不是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');
                }
            }
        });
    });
});

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

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

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

例如:

/ajax_helper.php?ts=3211321456

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

根据不同的应用程序,您现在可以使用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调用

我找到了一种解决方法,令我对其工作原理感到好奇。在阅读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,我将获得更新的内容。

虽然我的登录页面和注册页面在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中缓存该页面。

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

解决方案令人难以置信。请等待1秒钟,然后再次致电。在我们的测试中,只需要重复一次即可,但是我们编写的代码最多可以调用4次。我们不确定是否需要1s等待,但是我们不想冒重复呼叫的麻烦而给服务器增加负担。

我们发现问题发生在两个不同的AJAX调用上,分别调用了具有不同数据的不同API文件。但我担心它可能在任何AJAX调用中发生。我们只是不知道,因为我们不会检查每个AJAX结果,也不会在旧设备上多次测试每个呼叫。

这两个有问题的AJAX调用都在使用:POST,异步= true,setRequestHeader =(“内容类型”,“应用程序/ x-www-form-urlencoded”)

当问题发生时,通常只有一个AJAX调用正在进行。因此,这不是由于重叠的AJAX调用。有时问题是在设备繁忙时发生的,而有时不是在没有DevTools的情况下,我们真的不知道当时的情况。

iOS 13不会执行此操作,Chrome或Firefox也不会执行此操作。我们没有运行iOS 11或12的测试设备。也许其他人可以测试那些设备?

我在这里注意到这一点,因为此问题是搜索此问题时Google的最高结果。

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

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

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

本文地址:http://javascript.askforanswer.com/ios-6shangdesafarishifouhuancun-ajaxjieguo.html
文章标签: ,   ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!