Is Safari on iOS 6 caching $.ajax results?

2018-12-31 09:49发布

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

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:

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?


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 TimeStamp parameter 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!

25条回答
千与千寻千般痛.
2楼-- · 2018-12-31 10:12

I found one workaround that makes me curious as to why it works. Before reading Tadej's answer concerning ASP.NET web service, I was trying to come up with something that would work.

And I'm not saying that it's a good solution, but I just wanted to document it here.

main page: includes a JavaScript function, checkStatus(). The method calls another method which uses a jQuery AJAX call to update the html content. I used setInterval to call checkStatus(). Of course, I ran into the caching problem.

Solution: use another page to call the update.

On the main page, I set a boolean variable, runUpdate, and added the following to the body tag:

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

In the of helper.html:

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

So, if checkStatus() is called from the main page, I get the cached content. If I call checkStatus from the child page, I get updated content.

查看更多
无与为乐者.
3楼-- · 2018-12-31 10:13

This JavaScript snippet works great with jQuery and 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.

查看更多
零度萤火
4楼-- · 2018-12-31 10:14

While adding cache-buster parameters to make the request look different seems like a solid solution, I would advise against it, as it would hurt any application that relies on actual caching taking place. Making the APIs output the correct headers is the best possible solution, even if that's slightly more difficult than adding cache busters to the callers.

查看更多
牵手、夕阳
5楼-- · 2018-12-31 10:15

I was able to fix my problem by using a combination of $.ajaxSetup and appending a timestamp to the url of my post (not to the post parameters/body). This based on the recommendations of previous answers

$(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');
                }
            }
        });
    });
});
查看更多
笑指拈花
6楼-- · 2018-12-31 10:16

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

getThreadLocalResponse().setHeader("Cache-Control", "no-cache");
查看更多
无与为乐者.
7楼-- · 2018-12-31 10:17

In order to resolve this issue for WebApps added to the home screen, both of the top voted workarounds need to be followed. Caching needs to be turned off on the webserver to prevent new requests from being cached going forward and some random input needs to be added to every post request in order for requests that have already been cached to go through. Please refer to my post:

iOS6 - Is there a way to clear cached ajax POST requests for webapp added to home screen?

WARNING: to anyone who implemented a workaround by adding a timestamp to their requests without turning off caching on the server. If your app is added to the home screen, EVERY post response will now be cached, clearing safari cache doesn't clear it and it doesn't seem to expire. Unless someone has a way to clear it, this looks like a potential memory leak!

查看更多
登录 后发表回答