it-swarm.dev

Apakah Safari di iOS 6 memberikan hasil caching $ .ajax?

Sejak peningkatan ke iOS 6, kami melihat tampilan web Safari mengambil kebebasan dari caching panggilan $.ajax. Ini dalam konteks aplikasi PhoneGap sehingga menggunakan Safari WebView. Panggilan $.ajax kami adalah metode POST dan kami memiliki cache yang disetel ke {cache:false} palsu, tetapi ini masih terjadi. Kami mencoba menambahkan TimeStamp secara manual ke header tetapi tidak membantu.

Kami melakukan penelitian lebih lanjut dan menemukan bahwa Safari hanya mengembalikan hasil cache untuk layanan web yang memiliki fungsi tanda tangan yang statis dan tidak berubah dari panggilan ke panggilan. Misalnya, bayangkan fungsi yang disebut sesuatu seperti:

getNewRecordID(intRecordType)

Fungsi ini menerima parameter input yang sama berulang kali, tetapi data yang dikembalikan harus berbeda setiap waktu.

Harus terburu-buru Apple untuk membuat iOS 6 Zip bersama mengesankan mereka terlalu senang dengan pengaturan cache. Adakah orang lain yang melihat perilaku ini di iOS 6? Jika demikian, apa sebenarnya penyebabnya?


Solusi yang kami temukan adalah mengubah tanda tangan fungsi menjadi sesuatu seperti ini:

getNewRecordID(intRecordType, strTimestamp)

dan kemudian selalu mengirimkan parameter TimeStamp juga, dan hanya membuang nilai itu di sisi server. Ini mengatasi masalah ini. Saya harap ini membantu beberapa jiwa miskin lainnya yang menghabiskan 15 jam pada masalah ini seperti yang saya lakukan!

1049
user1684978

Setelah sedikit penyelidikan, ternyata Safari di iOS6 akan men-cache POST yang tidak memiliki header Kontrol-Cache atau bahkan "Kontrol-cache: max-age = 0".

Satu-satunya cara yang saya temukan untuk mencegah caching ini terjadi di tingkat global daripada harus meretas querystrings acak ke akhir panggilan layanan adalah dengan mengatur "Cache-Control: no-cache".

Begitu:

  • Tidak ada Cache-Control atau Expires header = iOS6 Safari akan melakukan cache
  • Cache-Control max-age = 0 dan Expired = iOS6 Safari akan cache
  • Kontrol Cache: no-cache = iOS6 Safari TIDAK akan melakukan cache

Saya menduga bahwa Apple mengambil keuntungan dari ini dari spec HTTP di bagian 9.5 tentang POST:

Respons terhadap metode ini tidak dapat di-cache, kecuali jika responsnya menyertakan bidang Cache-Control atau Expire header yang sesuai. Namun, respons 303 (Lihat Lainnya) dapat digunakan untuk mengarahkan agen pengguna untuk mengambil sumber daya yang dapat di-cache.

Jadi, secara teori Anda dapat menyimpan tanggapan POST ... yang tahu. Tapi tidak ada pembuat browser lain yang pernah berpikir itu akan menjadi ide bagus sampai sekarang. Tapi itu TIDAK menjelaskan caching ketika tidak ada header Kontrol-Cache atau Kedaluwarsa yang ditetapkan, hanya ketika ada beberapa set. Jadi itu pasti bug.

Di bawah ini adalah apa yang saya gunakan di bagian kanan konfigurasi Apache saya untuk menargetkan seluruh API saya karena ketika itu terjadi saya tidak benar-benar ingin melakukan cache apa pun, bahkan dapat. Yang saya tidak tahu adalah bagaimana mengatur ini hanya untuk POST.

Header set Cache-Control "no-cache"

Pembaruan: Saya perhatikan bahwa saya tidak menunjukkan bahwa itu hanya ketika POST sama, jadi ubah data atau URL POST mana saja dan Anda baik-baik saja. Jadi Anda bisa seperti yang disebutkan di tempat lain hanya menambahkan beberapa data acak ke URL atau sedikit data POST.

Pembaruan: Anda dapat membatasi "tanpa cache" hanya untuk POST jika Anda ingin seperti ini di Apache:

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

Saya harap ini bisa berguna untuk pengembang lain membenturkan kepala mereka ke dinding yang satu ini. Saya menemukan bahwa salah satu dari berikut ini mencegah Safari di iOS 6 dari caching respons POST:

  • menambahkan [cache-control: no-cache] di header permintaan
  • menambahkan parameter URL variabel seperti waktu saat ini
  • menambahkan [pragma: no-cache] di header respons
  • menambahkan [cache-control: no-cache] di header respons

Solusi saya adalah sebagai berikut dalam Javascript saya (semua permintaan AJAX saya adalah POST).

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

Saya juga menambahkan header [pragma: no-cache] ke banyak respons server saya.

Jika Anda menggunakan solusi di atas, ketahuilah bahwa setiap panggilan $ .ajax () yang Anda buat diatur ke global: false TIDAK akan menggunakan pengaturan yang ditentukan dalam $ .ajaxSetup (), jadi Anda perlu menambahkan header lagi.

145
Dave

Solusi sederhana untuk semua permintaan layanan web Anda, dengan asumsi Anda menggunakan 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()
    }));
});

Baca lebih lanjut tentang panggilan prefilter jQuery di sini .

Jika Anda tidak menggunakan jQuery, periksa dokumen untuk perpustakaan pilihan Anda. Mereka mungkin memiliki fungsi serupa.

66
Baz1nga

Saya baru saja mengalami masalah ini juga dalam aplikasi PhoneGap . Saya menyelesaikannya dengan menggunakan fungsi JavaScript getTime() dengan cara berikut:

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

Saya menghabiskan beberapa jam untuk mencari tahu ini. Akan menyenangkan bagi Apple untuk memberi tahu pengembang tentang masalah caching ini.

42
Bashevis

Saya memiliki masalah yang sama dengan aplikasi web yang mendapatkan data dari layanan web ASP.NET

Ini bekerja untuk saya:

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

Akhirnya, saya punya solusi untuk masalah unggahan saya.

Dalam JavaScript:

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

Di PHP :

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

Dari posting blog saya sendiri iOS 6.0 caching Ajax POST permintaan:

Cara memperbaikinya: Ada berbagai metode untuk mencegah caching permintaan. Metode yang direkomendasikan adalah menambahkan header no-cache. Ini adalah bagaimana hal itu dilakukan.

jQuery:

Periksa iOS 6.0 dan tetapkan tajuk Ajax seperti ini:

$.ajaxSetup({ cache: false });

ZeptoJS:

Periksa iOS 6.0 dan atur tajuk Ajax seperti ini:

$.ajax({
    type: 'POST',
    headers : { "cache-control": "no-cache" },
    url : ,
    data:,
    dataType : 'json',
    success : function(responseText) {…}

Sisi server

Jawa:

httpResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");

Pastikan untuk menambahkan ini di bagian atas halaman sebelum data dikirim ke klien.

.BERSIH

Response.Cache.SetNoStore();

Atau

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

Cuplikan JavaScript ini berfungsi baik dengan jQuery dan jQuery Mobile:

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

Cukup letakkan di suatu tempat dalam kode JavaScript Anda (setelah jQuery dimuat, dan yang terbaik sebelum Anda melakukan AJAX permintaan) dan itu akan membantu.

7
Jonathan

Anda juga dapat memperbaiki masalah ini dengan memodifikasi fungsi jQueryAjax dengan melakukan hal berikut (pada 1.7.1) ke atas fungsi Ajax (fungsi dimulai pada baris 7212 ). Perubahan ini akan mengaktifkan fitur anti-cache bawaan dari jQuery untuk semua permintaan POST.

(Skrip lengkap tersedia di http://dl.dropbox.com/u/58016866/jquery-1.7.1.js.)

Masukkan di bawah garis 7221:

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

Kemudian modifikasi berikut ini (mulai dari baris ~ 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 : "");
    }
}

Untuk:

// 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

Solusi cepat untuk layanan GWT-RPC adalah menambahkan ini ke semua metode jarak jauh:

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

Ini adalah pembaruan dari jawaban Baz1nga. Karena options.data bukan objek, tetapi string yang saya gunakan untuk menyatukan cap waktu:

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

Untuk mengatasi masalah ini untuk WebApps ditambahkan ke layar beranda, kedua solusi terpilih harus diikuti. Caching perlu dimatikan pada server web untuk mencegah permintaan baru agar tidak di-cache maju dan beberapa input acak perlu ditambahkan ke setiap permintaan posting agar permintaan yang sudah di-cache disimpan. Silakan merujuk ke posting saya:

iOS6 - Apakah ada cara untuk menghapus cache ajax POST permintaan untuk webapp ditambahkan ke layar beranda?

PERINGATAN: untuk siapa saja yang menerapkan solusi dengan menambahkan stempel waktu untuk permintaan mereka tanpa mematikan caching di server. Jika aplikasi Anda ditambahkan ke layar beranda, SETIAP respons pos sekarang akan di-cache, membersihkan cache safari tidak menghapusnya dan sepertinya tidak kedaluwarsa. Kecuali jika seseorang memiliki cara untuk membersihkannya, ini terlihat seperti potensi kebocoran memori!

4
fbader

Hal-hal yang TIDAK BEKERJA untuk saya dengan iPad 4/iOS 6:

Permintaan saya mengandung: Cache-Control: no-cache

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

Menambahkan cache: false ke panggilan ajax jQuery saya

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

Hanya ini yang berhasil:

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

Itulah yang harus dilakukan untuk 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

Solusi saya di ASP.NET (pagemethods, layanan web, dll.)

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

Sementara menambahkan parameter cache-buster untuk membuat permintaan tampak berbeda tampak seperti solusi yang solid, saya akan menyarankan untuk tidak melakukannya, karena itu akan merusak aplikasi yang bergantung pada caching aktual yang terjadi. Membuat API menghasilkan header yang benar adalah solusi terbaik, bahkan jika itu sedikit lebih sulit daripada menambahkan penghilang cache ke penelepon.

1
Ivo Jansch

Bagi mereka yang menggunakan Struts 1, berikut adalah cara saya memperbaiki masalah ini.

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

Saya pikir Anda sudah menyelesaikan masalah Anda, tetapi izinkan saya berbagi ide tentang caching web.

Memang benar Anda dapat menambahkan banyak header di setiap bahasa yang Anda gunakan, sisi server, sisi klien, dan Anda dapat menggunakan banyak trik lain untuk menghindari caching web, tetapi selalu berpikir bahwa Anda tidak pernah tahu dari mana klien terhubung ke server Anda, Anda tidak pernah tahu apakah dia menggunakan koneksi Hotel "Hot-Spot" yang menggunakan Squid atau produk caching lainnya.

Jika pengguna menggunakan proxy untuk menyembunyikan posisi aslinya, dll ... --- real satu-satunya cara untuk menghindari caching adalah cap waktu dalam permintaan juga jika tidak digunakan.

Sebagai contoh:

/ajax_helper.php?ts=3211321456

Maka setiap cache manager yang Anda harus lewati tidak menemukan URL yang sama di repositori cache dan kembali mengunduh konten halaman.

1
Lanello

Saya dapat memperbaiki masalah saya dengan menggunakan kombinasi $ .ajaxSetup dan menambahkan stempel waktu ke url posting saya (bukan ke parameter post/body). Ini berdasarkan rekomendasi dari jawaban sebelumnya

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

Di Ruby, Sinatra

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

Saya menemukan satu solusi yang membuat saya penasaran mengapa itu berhasil. Sebelum membaca jawaban Tadej mengenai layanan web ASP.NET, saya mencoba untuk membuat sesuatu yang bisa digunakan.

Dan saya tidak mengatakan itu solusi yang baik, tetapi saya hanya ingin mendokumentasikannya di sini.

halaman utama: termasuk fungsi JavaScript, checkStatus (). Metode ini memanggil metode lain yang menggunakan panggilan jQuery AJAX untuk memperbarui konten html. Saya menggunakan setInterval untuk memanggil checkStatus (). Tentu saja, saya mengalami masalah caching.

Solusi: gunakan halaman lain untuk memanggil pembaruan.

Di halaman utama, saya menetapkan variabel boolean, runUpdate, dan menambahkan yang berikut ini ke tag body:

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

Di helper.html:

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

Jadi, jika checkStatus () dipanggil dari halaman utama, saya mendapatkan konten yang di-cache. Jika saya memanggil checkStatus dari halaman anak, saya mendapatkan konten yang diperbarui.

0
CM Kanode

Tergantung pada aplikasinya, Anda dapat memecahkan masalah sekarang di iOS 6 menggunakan Safari> Advanced> Web Inspector sehingga membantu dengan situasi ini.

Hubungkan ponsel ke Safari di Mac dan kemudian gunakan menu pengembang untuk memecahkan masalah aplikasi web.

Bersihkan data situs web pada iPhone setelah pembaruan ke iOS6, termasuk khusus untuk aplikasi menggunakan Tampilan Web. Hanya satu aplikasi memiliki masalah dan ini diselesaikan selama pengujian IOS6 Beta jalan kembali, sejak itu tidak ada masalah nyata.

Anda mungkin perlu melihat aplikasi Anda juga, periksa NSURLCache jika di WebView di aplikasi khusus.

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

Saya kira tergantung pada sifat sebenarnya dari masalah Anda, implementasi, dll.

Ref: $ .ajax calls

0
Steven Strauss

Sementara halaman masuk dan pendaftaran saya berfungsi seperti pesona di Firefox, IE dan Chrome ... Saya telah berjuang dengan masalah ini di Safari untuk IOS dan OSX, beberapa bulan lalu saya menemukan solusi di SO.

<body onunload="">

ATAU via javascript

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

Ini adalah hal yang jelek tapi berhasil untuk sementara waktu.

Saya tidak tahu mengapa, tetapi mengembalikan null ke acara onunload halaman tidak di-cache di Safari.

0
Adriano Rosa