javascript - 失敗 - safari post 不具合




iOS 6のSafariは$.ajaxの結果をキャッシュしていますか? (17)

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

私たちはより多くの調査を行い、Safariは、静的で、呼び出しごとに変更されない機能シグネチャを持つWebサービスのキャッシュ結果を返すだけであることを発見しました。 例えば、次のような関数を想像してみてください。

getNewRecordID(intRecordType)

この関数は同じ入力パラメータを繰り返し受け取りますが、返されるデータは毎回異なるはずです。

iOS 6のジップを印象づけるために、アップルの急いでいる必要があります。キャッシュ設定にあまりにも満足しています。 他の誰かがiOS 6でこの動作を見ていますか? もしそうなら、正確にそれを引き起こしているのは何ですか?

私たちが見つけた回避策は、関数シグネチャを次のように変更することでした:

getNewRecordID(intRecordType, strTimestamp)

TimeStampパラメータを渡して、その値をサーバー側で破棄するだけです。 これは問題を回避します。 私はこれが私のようにこの問題に15時間を費やしている他の貧しい人々を助けてくれることを願っています!


GWT-RPCサービスの迅速な回避策は、これをすべてのリモートメソッドに追加することです。

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

RubyのSinatraで

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

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のプレフィルター呼び出しの詳細は、 here

jQueryを使用していない場合は、選択したライブラリのドキュメントを確認してください。 類似の機能を持つことがあります。


PhoneGapアプリケーションでもこの問題が発生しました。 JavaScript関数getTime()を次のように使用して解決しました。

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

私はこれを考え出して数時間を無駄にした。 このキャッシングの問題を開発者に通知することは、アップルにとってはいいことでした。


このJavaScriptスニペットはjQueryとjQuery Mobileでうまくいきます:

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

JavaScriptコードのどこかに配置してください(jQueryがロードされた後、AJAXリクエストを行う前に最適な場所に配置してください)。


この問題を解決するには、Ajax関数の先頭(関数は7212行目から開始)まで以下を実行してjQuery Ajax関数を修正します(1.7.1以降)。 この変更により、すべての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 : "");
}

これは、 IIS pragma:no-cacheヘッダーを追加した後でのみASP.NETで機能しました。 Cache-Control: no-cacheで十分ではありませんでした。


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

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

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

iOS6にアップデートした後、iPhoneのウェブサイトのデータを消去します。これには、ウェブビューを使用するアプリに固有の情報も含まれます。 1つのアプリだけが問題を抱えていましたが、これはIOS6ベータテストの途中で解決しました。

また、あなたのアプリを見て、カスタムアプリケーションの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コール


キャッシュバスターのパラメータを追加してリクエストを違うものに見せかけるのは固い解決策のようですが、実際のキャッシングに依存するアプリケーションを傷つけることになるので、私はそれに反対します。 呼び出し元にキャッシュバスターを追加するよりも少し難しい場合でも、APIを正しいヘッダーに出力することが可能です。


最後に、問題のアップロードに関する解決策があります。

JavaScriptの場合:

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

PHP

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

私のASP.NET回避策(pagemethods、webserviceなど)

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

私は、$ .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');
                }
            }
        });
    });
});

私は、ASP.NET Webサービスからデータを取得するwebappと同じ問題を抱えていました

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

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

私はこれが他の開発者がこの壁の壁に頭を打つのに使うことができることを願っています。 次のいずれかが、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]ヘッダを私のサーバレスポンスの多くに追加します。

上記の解決策を使用する場合は、$ .ajax()呼び出しがグローバルに設定されていることに注意してください。falseは$ .ajaxSetup()で指定された設定を使用しないため、ヘッダーを再度追加する必要があります。


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

そして私はそれが良い解決策であると言っているわけではありませんが、ここでそれを文書化したかっただけです。

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

解決策:別のページを使用して更新プログラムを呼び出します。

メインページでは、boolean変数runUpdateを設定し、bodyタグに以下を追加しました。

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

helper.htmlのthe:

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

したがって、メインページからcheckStatus()が呼び出されると、キャッシュされたコンテンツが取得されます。 子ページからcheckStatusを呼び出すと、更新されたコンテンツが取得されます。


関数シグネチャを次のように変更するための回避策を提案します。

getNewRecordID(intRecordType、strTimestamp)と入力し、常にTimeStampパラメータを渡して、サーバー側でその値を破棄します。 これは問題を回避します。





mobile-safari