1096

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

さらに調査を行った結果、Safari は、静的で呼び出しごとに変化しない関数シグネチャを持つ Web サービスのキャッシュされた結果のみを返すことがわかりました。たとえば、次のような関数を想像してください。

getNewRecordID(intRecordType)

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

Apple は急いで iOS 6 を高速化しようとしているに違いありませんが、彼らはキャッシュ設定に満足しすぎていました。他の誰かが iOS 6 でこの動作を見たことがありますか? もしそうなら、正確には何が原因ですか?


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

getNewRecordID(intRecordType, strTimestamp)

次に、常にTimeStampパラメーターも渡し、サーバー側でその値を破棄します。これにより、問題が回避されます。

4

25 に答える 25

449

少し調査した結果、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 はキャッシュしません

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

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

したがって、理論的には、POST 応答をキャッシュすることができます...誰が知っていましたか。しかし、これまでのところ、これが良いアイデアだと考えたブラウザー メーカーは他にありません。ただし、Cache-Control または Expires ヘッダーが設定されていない場合、キャッシュは考慮されず、設定されている場合のみです。だからバグに違いない。

以下は、API 全体をターゲットにするために Apache 構成の適切な部分で使用するものです。なぜなら、実際には何もキャッシュしたくないからです。私が知らないのは、これを POST だけに設定する方法です。

Header set Cache-Control "no-cache"

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

更新: Apache で次のようにしたい場合は、「キャッシュなし」を POST だけに制限できます。

SetEnvIf Request_Method "POST" IS_POST
Header set Cache-Control "no-cache" env=IS_POST
于 2012-09-20T16:06:19.120 に答える
148

これが、これで壁に頭をぶつけている他の開発者に役立つことを願っています。次のいずれかが原因で、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() で指定された設定を使用しないため、ヘッダーを再度追加する必要があることに注意してください。

于 2012-10-12T09:56:46.610 に答える
69

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 prefilter 呼び出しの詳細については、こちらをご覧ください。

jQuery を使用していない場合は、選択したライブラリのドキュメントを確認してください。同様の機能を備えている場合があります。

于 2012-09-21T08:53:07.397 に答える
44

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

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

これを理解するのに数時間を無駄にしました。このキャッシングの問題を開発者に通知することは、Apple にとって良いことでした。

于 2012-09-20T07:34:42.023 に答える
42

ASP.NET Webサービスからデータを取得するWebアプリケーションで同じ問題が発生しました

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

public WebService()
{
    HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    ...
}
于 2012-09-20T21:28:27.890 に答える
24

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

JavaScript の場合:

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

PHPの場合:

header('cache-control: no-cache');
于 2012-09-22T10:16:00.273 に答える
15

私自身のブログ投稿iOS 6.0 caching Ajax POST requests から:

修正方法: リクエストのキャッシュを防ぐには、さまざまな方法があります。推奨される方法は、no-cache ヘッダーを追加することです。これがその方法です。

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

サーバ側

ジャワ:

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.
于 2012-11-14T06:02:35.647 に答える
7

次の JavaScript スニペットは、jQuery および jQuery Mobile でうまく機能します。

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

JavaScript コードのどこかに配置するだけで (jQuery がロードされた後、AJAX 要求を実行する前が最適です)、役立つはずです。

于 2013-01-25T22:11:59.940 に答える
6

この問題は、jQuery Ajax関数を変更して、Ajax 関数の先頭 (関数は 7212 行目から開始) で次の (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 : "");
}
于 2012-09-27T14:30:19.170 に答える
5

これは 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();
  }
});
于 2012-10-25T12:32:47.980 に答える
5

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

getThreadLocalResponse().setHeader("Cache-Control", "no-cache");
于 2012-10-16T22:57:52.277 に答える
4

iPad 4/iOS 6 でうまくいかなかった点:

含む私の要求: Cache-Control:no-cache

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

cache: false を jQuery ajax 呼び出しに追加する

 $.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);
于 2013-04-29T06:43:01.680 に答える
4

ホーム画面に追加された WebApps のこの問題を解決するには、投票数の多かった両方の回避策に従う必要があります。新しいリクエストが今後キャッシュされないように、ウェブサーバーでキャッシュをオフにする必要があります。また、すでにキャッシュされているリクエストが処理されるように、すべてのポスト リクエストにランダムな入力を追加する必要があります。私の投稿を参照してください:

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

警告: サーバーのキャッシュをオフにせずにリクエストにタイムスタンプを追加することで回避策を実装した人へ。アプリがホーム画面に追加されると、すべての投稿応答がキャッシュされるようになり、サファリ キャッシュをクリアしてもクリアされず、有効期限が切れないようです。誰かがそれをクリアする方法を持っていない限り、これは潜在的なメモリ リークのように見えます!

于 2012-09-28T15:57:22.513 に答える
3

それが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);    
于 2012-10-12T06:55:45.497 に答える
2

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

protected void Application_BeginRequest(object sender, EventArgs e)
{
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
}
于 2012-09-24T13:10:51.593 に答える
1

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

}
于 2013-01-09T22:24:28.333 に答える
1

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

于 2012-09-24T07:39:33.970 に答える
1

$.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');
                }
            }
        });
    });
});
于 2013-01-19T17:27:18.520 に答える
1

すでに問題は解決されていると思いますが、Web キャッシングについてのアイデアを共有させてください。

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

ユーザーがプロキシを使用して自分の実際の位置などを隠している場合、キャッシュを回避する唯一の方法は、未使用の場合でもリクエストのタイムスタンプです。

例えば:

/ajax_helper.php?ts=3211321456

次に、パスする必要があるすべてのキャッシュ マネージャーが、キャッシュ リポジトリで同じ URL を見つけられず、ページ コンテンツを再ダウンロードします。

于 2014-06-12T16:40:18.693 に答える
0

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

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

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

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

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

于 2012-10-08T15:54:21.610 に答える
0

アプリによっては、iOS 6 で [Safari] > [Advanced] > [Web Inspector] を使用して問題をトラブルシューティングできるため、この状況で役立ちます。

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

iOS6 へのアップデート後に、Web ビューを使用するアプリ固有のものを含め、iPhone 上の Web サイト データを消去します。問題があったのは 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

問題の本質、実装などに応じて推測します..

参照: $.ajax 呼び出し

于 2012-09-21T21:57:13.430 に答える
-1

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

于 2012-09-24T22:05:41.437 に答える
-2

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

getNewRecordID(intRecordType, strTimestamp) を取得し、常に TimeStamp パラメータも渡し、サーバー側でその値を破棄します。これにより、問題が回避されます。

于 2016-07-28T16:33:15.027 に答える