web-dev-qa-db-ja.com

IOS 6上のSafariは$ .ajax結果をクラッシュしますか?

IOS 6にアップグレードして以来、SafariのWebビューは$.ajax呼び出しをキャッシュするという自由を取っています。これは、サファリのWebViewを使用しているので、PhoneGapのアプリケーションのコンテキストです。私たちの$.ajax呼び出しはPOSTメソッドであり、キャッシュはfalseに設定されています{cache:false}、しかしそれでもまだ起こっています。私たちは、ヘッダにTimeStampを追加し、手動で試してみましたが、それは助けにはなりませんでした。

私たちは、より多くの研究を行なったし、Safariが唯一の静的であり、呼び出すために呼び出しから変更されません関数のシグネチャを持つWebサービスのためのキャッシュされた結果を返していることがわかりました。例えば、何かのように呼ばれる関数を想像してみてください。

getNewRecordID(intRecordType)

この関数は何度も何度も同じ入力パラメータを受け取り、それが返すデータは、毎回異なっている必要があります。

彼らはキャッシュ設定とあまりにも幸せだ印象に沿ってのiOS 6ジップを作るために、Appleの急いでなければなりません。他の誰は、iOS 6でこの動作を見ていますか?もしそうなら、まさにそれを引き起こしていますか?


私たちが見つかった問題を回避するには、このようなものにするために、関数のシグネチャを変更することでした。

getNewRecordID(intRecordType, strTimestamp)

その後、いつものようにもTimeStampパラメータを渡すと、ちょうどサーバー側でその値を破棄します。これは、問題を回避します。私は、これは私が行ったように、この問題に15時間を費やしている他のいくつかの貧しい魂に役立ちます願っています!

1049
user1684978

ちょっと調べてみると、iOS6上のSafariはCache-Controlヘッダも "Cache-Control:max-age = 0"もないPOSTをキャッシュするでしょう。

ランダムなクエリ文字列をサービスコールの終わりにハッキングするよりも、このキャッシュがグローバルレベルで行われるのを防ぐ唯一の方法は、 "Cache-Control:no-cache"を設定することです。

そう:

  • Cache-ControlまたはExpiresヘッダがない= iOS6 Safariはキャッシュします
  • Cache-Control max-age = 0で即時Expires = iOS6 Safariはキャッシュします
  • Cache-Control:no-cache = iOS6 Safariはキャッシュしません

私は、AppleがPOSTについてのセクション9.5のHTTP仕様からこれを利用していると思います。

応答に適切なCache-ControlまたはExpiresヘッダーフィールドが含まれていない限り、このメソッドに対する応答はキャッシュできません。しかし、303(See See)応答を使用して、ユーザーエージェントにキャッシュ可能なリソースを取得するように指示できます。

理論的にはPOSTレスポンスをキャッシュすることができます。しかし、今まで他のブラウザメーカーがこれが良い考えだとは考えていませんでした。ただし、Cache-ControlヘッダーまたはExpiresヘッダーが設定されていない場合はキャッシュが考慮されません。設定がある場合のみです。だからそれはバグに違いない。

以下は、私が自分のAPI全体をターゲットにするために私のApache設定の正しい部分で使用しているものです。私が知らないのはPOSTのためだけにこれを設定する方法です。

Header set Cache-Control "no-cache"

更新:POSTが同じであることだけを指摘していないことに気付いたので、POSTデータまたはURLを変更すれば問題ありません。そのため、他の場所で説明したように、URLにランダムなデータまたはPOST dataを少し追加するだけで済みます。

更新日:Apacheでこのようにしたい場合は、 "no-cache"をPOSTに限定することができます。

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

私はこれが壁に頭をぶつけている他の開発者にとって役に立つことを願っています。私は、iOS 6上のSafariがPOST応答をキャッシュするのを防ぐために、以下のいずれかを行っています。

  • リクエストヘッダに[cache-control:no-cache]を追加する
  • 現在時刻などの可変URLパラメータを追加する
  • レスポンスヘッダに[pragma:no-cache]を追加する
  • 応答ヘッダに[cache-control:no-cache]を追加する

私のJavascriptでは、私の解決策は次のとおりです(私のすべてのAJAX要求はPOSTです)。

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

私は[pragma:no-cache]ヘッダを私のサーバレスポンスの多くに追加しています。

上記の解決策を使用する場合、global:falseに設定された$ .ajax()呼び出しはすべて$ .ajaxSetup()で指定された設定を使用しないので、ヘッダーを再度追加する必要があります。

145
Dave

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プレフィルター呼び出しについての詳細を読んでください ここ

JQueryを使用していない場合は、選択したライブラリのドキュメントを確認してください。彼らは同様の機能を持っているかもしれません。

66
Baz1nga

私は PhoneGap アプリケーションでも同様にこの問題を抱えていました。私は次のようにJavaScript関数getTime()を使って解決しました。

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

私はこれを考え出して数時間を無駄にしました。このキャッシュの問題を開発者に通知していただければ幸いです。

42
Bashevis

私は、WebアプリケーションがASP.NET Webサービスからデータを取得するのと同じ問題を抱えていました

これは私のために働いた:

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

最後に、アップロードに関する問題を解決しました。

JavaScriptの場合:

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

_ php _ :に

header('cache-control: no-cache');
23
goker.cebeci

私のブログ記事から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.
14
kiranvj

このJavaScriptスニペットは、jQueryおよびjQuery Mobileとうまく連携します。

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

JavaScriptコードのどこかに(jQueryがロードされた後、AJAXリクエストを実行する前に)配置するだけで問題ありません。

7
Jonathan

Ajax関数の先頭に次のようにして(1.7.1以降) jQueryAjax 関数を変更することでもこの問題を解決できます(関数は7212行目で始まります)。この変更により、すべてのPOST要求に対してjQueryの組み込みアンチキャッシュ機能が有効になります。

(完全なスクリプトはhttp://dl.dropbox.com/u/58016866/jquery-1.7.1.jsにあります。)

行7221の下に挿入します。

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

その後、以下を修正してください(7474行目以降)。

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 : "");
}
6
Sam Shiles

GWT-RPCサービスのための簡単な回避策はこれをすべてのリモートメソッドに追加することです:

getThreadLocalResponse().setHeader("Cache-Control", "no-cache");
5
Lars Høidahl

これは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();
  }
});
5
remcoder

ホーム画面に追加されたWebAppについてこの問題を解決するには、両方のトップ投票回避策に従う必要があります。新しいリクエストが今後キャッシュされるのを防ぐためにWebサーバでキャッシングをオフにする必要があります。また、すでにキャッシュされたリクエストを処理するには、すべての投稿リクエストにランダム入力を追加する必要があります。私の投稿を参照してください。

iOS6 - キャッシュされたajax POSTホームアプリケーションに追加されたWebアプリケーションへのリクエストをクリアする方法はありますか?

警告:サーバーのキャッシュをオフにせずに自分の要求にタイムスタンプを追加することによって回避策を実行した人への警告。あなたのアプリがホーム画面に追加された場合、EVERYポストレスポンスはキャッシュされます。サファリキャッシュをクリアしてもクリアされず、期限切れにはなりません。誰かがそれをクリアする方法を持っていない限り、これは潜在的なメモリリークのように見えます!

4
fbader

DID動作しないこと 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);
3
Brian Ogden

それは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);    
3
Spiff

ASP.NET (pagemethods、Webサービスなど)での私の回避策

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

リクエストを異なるように見せるためにキャッシュバスターパラメータを追加することは確かな解決策のように思えますが、実際のキャッシュに依存しているアプリケーションを傷つける可能性があるので、私はそれに対してお勧めします。 APIに正しいヘッダーを出力させることは、呼び出し側にキャッシュバスターを追加するよりも少し難しい場合でも、可能な限り最良の解決策です。

1
Ivo Jansch

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

}
1
cbmeeks

私はあなたがあなたの問題をすでに解決したと思いますが、私はウェブキャッシングについての考えを共有させてください。

サーバー側、クライアント側で使用する言語ごとに多数のヘッダーを追加でき、Webキャッシングを回避するために他の多くのトリックを使用できますが、クライアントがサーバーに接続している場所からは決してわかりません。彼がSquidまたは他のキャッシュ製品を使用するホテルの「ホットスポット」接続を使用しているかどうかはわかりません。

ユーザーが自分の本当の位置などを隠すためにプロキシを使用している場合…キャッシングを避けるための real の唯一の方法は、未使用の場合でも要求内のタイムスタンプです。

例えば:

/ajax_helper.php?ts=3211321456

それからあなたが渡さなければならないすべてのキャッシュマネージャは、キャッシュレポジトリの中で同じURLを見つけて、そしてページコンテンツを再ダウンロードすることはしませんでした。

1
Lanello

$ .ajaxSetupを組み合わせて使用​​し、投稿のURLにタイムスタンプを追加することで問題を解決することができました(投稿のパラメータや本文には追加されません)。これは以前の回答の推奨に基づいています

$(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');
                }
            }
        });
    });
});
1

ルビーのシナトラ

before '*' do
  if env['REQUEST_METHOD'] == 'POST'
    headers 'Cache-Control' => 'no-cache, no-store, must-revalidate'
  end
end
0
jchook

私はそれがなぜうまくいくのかについて興味をそそる1つの回避策を見つけました。 ASP.NET Webサービスに関するTadejの回答を読む前に、私はうまくいくものを考え出そうとしていました。

それが良い解決策だとは言っていませんが、ここでそれを文書化したいと思いました。

メインページ:JavaScript関数checkStatus()を含みます。このメソッドは、jQuery AJAX呼び出しを使用してHTMLコンテンツを更新する別のメソッドを呼び出します。 checkStatus()を呼び出すためにsetIntervalを使用しました。もちろん、私はキャッシュの問題に出くわしました。

解決策:別のページを使ってアップデートを呼び出してください。

メインページで、ブール変数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を呼び出すと、更新されたコンテンツが表示されます。

0
CM Kanode

アプリによっては、iOS 6でSafari> Advanced> Web Inspectorを使用して問題を解決することができますので、この状況では役に立ちます。

電話をMacのSafariに接続してから、開発者メニューを使用してWebアプリケーションのトラブルシューティングを行います。

IOS 6にアップデートした後、iPhone上のWebサイトのデータを消去します。これにはWebビューを使用しているアプリに固有のものも含まれます。 1つのアプリだけが問題を抱えていました、そして、これは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

私はあなたの問題の真の性質、実装などに依存していると思います。

Ref:$ .ajaxの呼び出し

0
Steven Strauss

私のログインページとサインアップページはFirefox、IE、Chromeの魅力のように機能しますが、SafariではIOSとOSXの問題で数ヶ月前に苦労しています。 SOで回避策を見つけました。

<body onunload="">

またはJavaScriptを介して

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

これはちょっと醜いことですがしばらくの間うまくいきます。

理由はわかりませんが、onunloadイベントにnullを返してもページがSafariにキャッシュされません。

0
Adriano Rosa