perhaps? 2012-09-19 22:07 采纳率: 100%
浏览 1939

6 caching / . Ajax 检测结果?

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!

转载于:https://stackoverflow.com/questions/12506897/is-safari-on-ios-6-caching-ajax-results

  • 写回答

25条回答 默认 最新

  • 零零乙 2012-09-19 23:34
    关注

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

    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.

    评论
  • ~Onlooker 2012-09-20 08:06
    关注

    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".

    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

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

    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.

    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.

    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.

    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.

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

    SetEnvIf Request_Method "POST" IS_POST
    Header set Cache-Control "no-cache" env=IS_POST
    
    评论
  • from.. 2012-09-20 13:28
    关注

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

    This worked for me:

    public WebService()
    {
        HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
        ...
    }
    
    评论
  • Didn"t forge 2012-09-21 00:53
    关注

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

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

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

    评论
  • 零零乙 2012-09-21 13:57
    关注

    Depending on the app you can trouble shoot the issue now in iOS 6 using Safari>Advanced>Web Inspector so that is helpful with this situation.

    Connect the phone to Safari on a Mac an then use the developer menu to trouble shoot the web app.

    Clear the website data on the iPhone after update to iOS6, including specific to the app using a Web View. Only one app had an issue and this solved it during IOS6 Beta testing way back, since then no real problems.

    You may need to look at your app as well, check out NSURLCache if in a WebView in a custom app.

    https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSURLCache_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003754

    I guess depending on the true nature of your problem, implementation, etc. ..

    Ref: $.ajax calls

    评论
  • Didn"t forge 2012-09-22 02:16
    关注

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

    In JavaScript:

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

    In PHP:

    header('cache-control: no-cache');
    
    评论
  • 关注

    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.

    评论
  • 旧行李 2012-09-24 05:10
    关注

    My workaround in ASP.NET (pagemethods, webservice, etc.)

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        Response.Cache.SetCacheability(HttpCacheability.NoCache);
    }
    
    评论
  • bug^君 2012-09-24 14:05
    关注

    It worked with ASP.NET only after adding the pragma:no-cache header in IIS. Cache-Control: no-cache was not enough.

    评论
  • YaoRaoLov 2012-09-27 06:30
    关注

    You can also fix this issue by modifying the jQuery Ajax function 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.

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

    Insert below line 7221:

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

    Then modify the following (starting at line ~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 : "");
        }
    }
    

    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, "$1_=" + ts);
    
        // If nothing was replaced, add timestamp to the end.
        s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
    }
    

    展开全部

    评论
  • 衫裤跑路 2012-09-28 07:57
    关注

    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!

    评论
  • 笑故挽风 2012-10-08 07:54
    关注

    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.

    评论
  • ℙℕℤℝ 2012-10-11 22:55
    关注

    That's the work around for 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);    
    
    评论
  • perhaps? 2012-10-12 01:56
    关注

    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:

    • 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

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

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

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

    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.

    评论
  • derek5. 2012-10-16 14:57
    关注

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

    getThreadLocalResponse().setHeader("Cache-Control", "no-cache");
    
    评论
  • ?yb? 2012-10-25 04:32
    关注

    This is an update of Baz1nga's answer. Since options.data is not an object but a string I just resorted to concatenating the timestamp:

    $.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();
      }
    });
    
    评论
  • 斗士狗 2012-11-13 22:02
    关注

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

    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.

    jQuery:

    Check for iOS 6.0 and set Ajax header like this:

    $.ajaxSetup({ cache: false });
    

    ZeptoJS:

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

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

    header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1.
    header('Pragma: no-cache'); // HTTP 1.0.
    
    评论
  • elliott.david 2013-01-09 14:24
    关注

    For those that use Struts 1, here is how I fixed the issue.

    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() {
        }
    
    }
    

    展开全部

    评论
  • MAO-EYE 2013-01-19 09:27
    关注

    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');
                    }
                }
            });
        });
    });
    
    评论
  • 关注

    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.

    评论
  • csdnceshi62 2013-04-28 22:43
    关注

    Things that DID NOT WORK for me with an iPad 4/iOS 6:

    My request containing: Cache-Control:no-cache

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

    Adding cache: false to my jQuery ajax call

     $.ajax(
            {
                url: postUrl,
                type: "POST",
                cache: false,
                ...
    

    Only this did the trick:

    var currentTime = new Date();
    var n = currentTime.getTime();
    postUrl = "http://www.example.com/test.php?nocache="+n;
    $.post(postUrl, callbackFunction);
    
    评论
  • ?yb? 2014-06-12 08:40
    关注

    I think you have already resolved your issue, but let me share an idea about web caching.

    It is true you can add many headers in each language you use, server side, client side, and you can use many other tricks to avoid web caching, but always think that you can never know from where the client are connecting to your server, you never know if he are using a Hotel “Hot-Spot” connection that uses Squid or other caching products.

    If the users are using proxy to hide his real position, etc… the real only way to avoid caching is the timestamp in the request also if is unused.

    For example:

    /ajax_helper.php?ts=3211321456
    

    Then every cache manager you have to pass didnt find the same URL in the cache repository and go re-download the page content.

    评论
  • ~Onlooker 2014-07-19 13:12
    关注

    While my login and signup pages works like a charm in Firefox, IE and Chrome... I've been struggling with this issue in Safari for IOS and OSX, few months ago I found a workaround on the SO.

    <body onunload="">
    

    OR via javascript

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

    This is kinda ugly thing but works for a while.

    I don't know why, but returning null to the onunload event the page do not get cached in Safari.

    评论
  • from.. 2015-03-01 21:12
    关注

    In Ruby's Sinatra

    before '*' do
      if env['REQUEST_METHOD'] == 'POST'
        headers 'Cache-Control' => 'no-cache, no-store, must-revalidate'
      end
    end
    
    评论
  • 旧行李 2016-07-28 08:33
    关注

    I suggest a workaround 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.

    评论
编辑
预览

报告相同问题?

悬赏问题

  • ¥15 MacOS 80端口外网无法访问
  • ¥50 js逆转反解密-会的来
  • ¥15 wrodpress如何调取数据库并展示
  • ¥15 python梯形积分与GPS测得位移使用卡尔曼滤波融合问题
  • ¥15 匈牙利算法分割求损失问题
  • ¥30 ABAQUS 实体单元如何在分析步中分步多次施加绕某轴的运动?
  • ¥15 docker部署redis集群,springboot启动报错DefaultClusterTopologyRefresh,而且第一个节点的IP也变了
  • ¥15 关于延迟常微分方程DDE的分岔图
  • ¥15 putimage函数输出错误
  • ¥15 进行刷新动态页面和点击进入一个动态,会包含在一个网络五元组会话内吗
手机看
程序员都在用的中文IT技术交流社区

程序员都在用的中文IT技术交流社区

专业的中文 IT 技术社区,与千万技术人共成长

专业的中文 IT 技术社区,与千万技术人共成长

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

客服 返回
顶部