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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12506897/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 10:34:11  来源:igfitidea点击:

Is Safari on iOS 6 caching $.ajax results?

javascriptjqueryajaxcachingmobile-safari

提问by user1684978

Since the upgrade to iOS 6, we are seeing Safari's web view take the liberty of caching $.ajaxcalls. This is in the context of a PhoneGap application so it is using the Safari WebView. Our $.ajaxcalls are POSTmethods and we have cache set to false {cache:false}, but still this is happening. We tried manually adding a TimeStampto the headers but it did not help.

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

We did more research and found that Safari is only returning cached results for web services that have a function signature that is static and does not change from call to call. For instance, imagine a function called something like:

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

getNewRecordID(intRecordType)

This function receives the same input parameters over and over again, but the data it returns should be different every time.

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

Must be in Apple's haste to make iOS 6 zip along impressively they got too happy with the cache settings. Has anyone else seen this behavior on iOS 6? If so, what exactly is causing it?

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



The workaround that we found was to modify the function signature to be something like this:

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

getNewRecordID(intRecordType, strTimestamp)

and then always pass in a TimeStampparameter as well, and just discard that value on the server side. This works around the issue. I hope this helps some other poor soul who spends 15 hours on this issue like I did!

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

回答by Kieran

After a bit of investigation, turns out that Safari on iOS6 will cache POSTs that have either no Cache-Control headers or even "Cache-Control: max-age=0".

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

The only way I've found of preventing this caching from happening at a global level rather than having to hack random querystrings onto the end of service calls is to set "Cache-Control: no-cache".

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

So:

所以:

  • No Cache-Control or Expires headers = iOS6 Safari will cache
  • Cache-Control max-age=0 and an immediate Expires = iOS6 Safari will cache
  • Cache-Control: no-cache = iOS6 Safari will NOT cache
  • 没有 Cache-Control 或 Expires 标头 = iOS6 Safari 将缓存
  • Cache-Control max-age=0 并且立即 Expires = iOS6 Safari 将缓存
  • 缓存控制:no-cache = iOS6 Safari 不会缓存

I suspect that Apple is taking advantage of this from the HTTP spec in section 9.5 about POST:

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

Responses to this method are not cacheable, unless the response includes appropriate Cache-Control or Expires header fields. However, the 303 (See Other) response can be used to direct the user agent to retrieve a cacheable resource.

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

So in theory you can cache POST responses...who knew. But no other browser maker has ever thought it would be a good idea until now. But that does NOT account for the caching when no Cache-Control or Expires headers are set, only when there are some set. So it must be a bug.

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

Below is what I use in the right bit of my Apache config to target the whole of my API because as it happens I don't actually want to cache anything, even gets. What I don't know is how to set this just for POSTs.

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

Header set Cache-Control "no-cache"

Update: Just noticed that I didn't point out that it is only when the POST is the same, so change any of the POST data or URL and you're fine. So you can as mentioned elsewhere just add some random data to the URL or a bit of POST data.

更新:刚刚注意到我没有指出只有当 POST 相同时,所以更改任何 POST 数据或 URL 就可以了。所以你可以像其他地方提到的那样只向 URL 添加一些随机数据或一些 POST 数据。

Update: You can limit the "no-cache" just to POSTs if you wish like this in Apache:

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

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

回答by Dave

I hope this can be of use to other developers banging their head against the wall on this one. I found that any of the following prevents Safari on iOS 6 from caching the POST response:

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

  • adding [cache-control: no-cache] in the request headers
  • adding a variable URL parameter such as the current time
  • adding [pragma: no-cache] in the response headers
  • adding [cache-control: no-cache] in the response headers
  • 在请求头中添加 [cache-control: no-cache]
  • 添加一个可变的 URL 参数,例如当前时间
  • 在响应头中添加 [pragma: no-cache]
  • 在响应头中添加 [cache-control: no-cache]

My solution was the following in my Javascript (all my AJAX requests are POST).

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

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

I also add the [pragma: no-cache] header to many of my server responses.

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

If you use the above solution be aware that any $.ajax() calls you make that are set to global: false will NOT use the settings specified in $.ajaxSetup(), so you will need to add the headers in again.

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

回答by Baz1nga

Simple solution for all your web service requests, assuming you're using jQuery:

假设您使用的是 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()
    }));
});

Read more about the jQuery prefilter call here.

在此处阅读有关 jQuery 预过滤器调用的更多信息。

If you aren't using jQuery, check the docs for your library of choice. They may have similar functionality.

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

回答by Bashevis

I just had this issue as well in a PhoneGapapplication. I solved it by using the JavaScript function getTime()in the following manner:

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

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

I wasted a few hours figuring this out. It would have been nice of Apple to notify developers of this caching issue.

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

回答by Tadej

I had the same problem with a webapp getting data from ASP.NET webservice

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

This worked for me:

这对我有用:

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

回答by goker.cebeci

Finally, I've a solution to my uploading problem.

最后,我找到了上传问题的解决方案。

In JavaScript:

在 JavaScript 中:

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

In PHP:

PHP 中

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

回答by kiranvj

From my own blog post iOS 6.0 caching Ajax POST requests:

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

How to fix it: There are various methods to prevent caching of requests. The recommended method is adding a no-cache header. This is how it is done.

如何修复:有多种方法可以防止缓存请求。推荐的方法是添加一个 no-cache 标头。这是如何完成的。

jQuery:

jQuery:

Check for iOS 6.0 and set Ajax header like this:

检查 iOS 6.0 并像这样设置 Ajax 标头:

$.ajaxSetup({ cache: false });

ZeptoJS:

ZeptoJS:

Check for iOS 6.0 and set the Ajax header like this:

检查 iOS 6.0 并像这样设置 Ajax 标头:

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

Server side

服务器端

Java:

爪哇:

httpResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");

Make sure to add this at the top the page before any data is sent to the client.

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

.NET

。网

Response.Cache.SetNoStore();

Or

或者

Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);

PHP

PHP

header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1.
header('Pragma: no-cache'); // HTTP 1.0.

回答by Jonathan

This JavaScript snippet works great with jQuery and jQuery Mobile:

这个 JavaScript 片段非常适合 jQuery 和 jQuery Mobile:

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

Just place it somewhere in your JavaScript code (after jQuery is loaded, and best before you do AJAX requests) and it should help.

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

回答by Sam Shiles

You can also fix this issue by modifying the jQueryAjaxfunction by doing the following (as of 1.7.1) to the top of the Ajax function (function starts at line 7212). This change will activate the built-in anti-cache feature of jQuery for all POST requests.

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

(The full script is available at http://dl.dropbox.com/u/58016866/jquery-1.7.1.js.)

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

Insert below line 7221:

在第 7221 行下方插入:

if (options.type === "POST") {
    options.cache = false;
}

Then modify the following (starting at line ~7497).

然后修改以下内容(从 ~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, "_=" + ts);

        // If nothing was replaced, add timestamp to the end.
        s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
    }
}

To:

到:

// 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, "_=" + ts);

    // If nothing was replaced, add timestamp to the end.
    s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
}

回答by Lars H?idahl

A quick work-around for GWT-RPC services is to add this to all the remote methods:

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

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