javascript - iOS 6'da Safari, $.ajax sonuçlarını önbelleğe alıyor mu?


iOS 6’ya yükseltmeden bu yana, Safari’nin web görüntüleyicisinin $.ajax çağrılarını önbelleğe alma özgürlüğünü aldığını görüyoruz. Bu, Safari WebView kullanan bir PhoneGap uygulaması bağlamında oluyor. Bizim $.ajax çağrılarımız POST yöntemleri ve önbellek ayarını false olarak belirledik {cache:false}, ama yine de bu oluyor. Başlıklara manuel olarak bir TimeStamp eklemeyi denedik ama işe yaramadı.

Daha fazla araştırma yaptık ve Safari'nin yalnızca çağrıdan çağrıya değişmeyen ve statik olan bir işlev imzasına sahip web servisleri için önbelleğe alınmış sonuçları döndürdüğünü bulduk. Örneğin, şöyle bir işlev düşünün:

getNewRecordID(intRecordType)

Bu fonksiyon aynı giriş parametrelerini tekrar tekrar alır, ancak döndürdüğü veriler her seferinde farklı olmalıdır.

iOS 6'nın hızla çalışmasını sağlamak için Apple acele etmiş olmalı ki, önbellek ayarlarıyla fazlasıyla coşmuşlar. Başka birisi bunu iOS 6’da gördü mü? Eğer gördüyse, buna tam olarak ne sebep oluyor?


Bulduğumuz geçici çözüm, fonksiyon imzasını şöyle bir şey olacak şekilde değiştirmekti:

getNewRecordID(intRecordType, strTimestamp)

ve sonra her zaman bir TimeStamp parametresini de gönderin ve sunucu tarafında bu değeri sadece atın. Bu, sorunun önüne geçer.

Cevap #1

Biraz araştırmadan sonra, iOS6'da Safari'nin ya Cache-Control başlığı olmayan ya da hatta "Cache-Control: max-age=0" olan POSTları önbelleğe alacağı ortaya çıktı.

Bunu, servislere rastgele sorgu dizeleri eklemek zorunda kalmadan küresel düzeyde önlemenin bulduğum tek yolu, "Cache-Control: no-cache" ayarlamaktır.

Yani :

  • Cache-Control veya Expires başlıkları yok=iOS6 Safari önbelleğe alacak
  • Cache-Control max-age=0 ve hemen bir Expires=iOS6 Safari önbelleğe alacaktır
  • Cache-Control: no-cache=iOS6 Safari önbelleğe almayacaktır

Apple'ın bunu POST hakkındaki 9.5 bölümündeki HTTP spesifikasyonundan yararlandığını düşünüyorum:

Bu metoda verilen yanıtlar, yanıt uygun Cache-Control veya Expires başlık alanlarını içermedikçe önbelleğe alınamaz. Ancak, 303 (See Other) yanıtı, kullanıcı aracını önbelleğe alınabilir bir kaynağı alması için yönlendirmek amacıyla kullanılabilir.

Yani teoride POST yanıtlarını önbelleğe alabilirsiniz... kim bilir. Ama şimdiye kadar başka hiçbir tarayıcı üreticisi bunun iyi bir fikir olacağını düşünmemişti. Ama bu, Cache-Control veya Expires başlıkları ayarlanmadığında önbelleğe alma durumunu kapsamaz, sadece bazıları ayarlandığında geçerlidir. Yani bu mutlaka bir hata olmalı.

Aşağıda, Apache yapılandırmamın sağ tarafında API'min tamamını hedeflemek için kullandığım şey var çünkü aslında hiçbir şeyi, hatta GET isteklerini bile önbelleğe almak istemiyorum. Bilmediğim şey ise bunu sadece POST istekleri için nasıl ayarlayacağım.

Header set Cache-Control "no-cache"

Güncelleme: POST aynı olduğunda geçerli olduğunu belirtmediğimi fark ettim, bu yüzden POST verilerinden veya URL'den herhangi birini değiştirirseniz sorun olmaz. Yani başka bir yerde bahsedildiği gibi, URL'ye biraz rastgele veri ekleyebilir veya biraz POST verisi ekleyebilirsiniz.

Güncelleme: İsterseniz Apache'de bunu sadece POST'lara sınırlayarak "no-cache" uygulayabilirsiniz:

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

Cevap #2

Umarım bu, bu konuda kafasını duvara vura vura uğraşan diğer geliştiricilere faydalı olur. iOS 6'da Safari'nin POST yanıtını önbelleğe almasını engelleyen şeylerden herhangi birini buldum:

  • istek başlıklarına [cache-control: no-cache] eklemek
  • mevcut zaman gibi değişken bir URL parametresi eklemek
  • yanıt başlıklarına [pragma: no-cache] eklemek
  • yanıt başlıklarına [cache-control: no-cache] eklemek

Benim çözümüm Javascript'imde aşağıdaki gibiydi (tüm AJAX isteklerim POST’tur).

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

Ayrıca birçok sunucu yanıtıma [pragma: no-cache] başlığını da ekliyorum.

Yukarıdaki çözümü kullanırsanız, global: false olarak ayarlanmış herhangi bir $.ajax() çağrısının $.ajaxSetup() ile belirtilen ayarları kullanmayacağını unutmayın, bu nedenle başlıkları tekrar eklemeniz gerekecektir.

Cevap #3

jQuery kullandığınızı varsayarsak, web servis talepleriniz için basit çözüm:

$.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 önyükleyici çağrısı hakkında daha fazlasını burada okuyun.

jQuery kullanmıyorsanız, tercih ettiğiniz kütüphanenin belgelerine bakın. Benzer işlevselliğe sahip olabilirler.

Cevap #4

Ben de bir PhoneGap uygulamasında aynı sorunu yaşadım. Bunu şu şekilde JavaScript fonksiyonu getTime() kullanarak çözdüm:

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

Bunu çözmek için birkaç saat harcadım. Apple'ın geliştiricileri bu önbellekleme sorunu hakkında bilgilendirmesi güzel olurdu.

Cevap #5

ASP.NET web servisinden veri alan bir web uygulamasıyla aynı sorunu yaşamıştım

Bu benim için işe yaradı:

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

Cevap #6

Nihayet, yükleme sorunuma bir çözüm buldum.

JavaScript'te:

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

PHP'de:

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

Cevap #7

Kendi blog yazımdan iOS 6.0 Ajax POST isteklerini önbelleğe alma:

Nasıl düzeltilir: İsteklerin önbelleğe alınmasını önlemek için çeşitli yöntemler vardır. Önerilen yöntem, no-cache başlığı eklemektir. İşte nasıl yapıldığı.

###jQuery:

iOS 6.0 için kontrol edin ve Ajax başlığını şöyle ayarlayın:

$.ajaxSetup({ cache: false });

###ZeptoJS:

iOS 6.0 için kontrol edin ve Ajax başlığını şöyle ayarlayın:

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

##Sunucu tarafı

###Java:

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

Bu veriler istemciye gönderilmeden önce sayfanın en üstüne eklediğinizden emin olun.

###.NET

Response.Cache.SetNoStore();

Veya

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.

İlgili makaleler