Cegah caching browser dari hasil panggilan AJAX

262

Sepertinya jika saya memuat konten dinamis menggunakan $.get(), hasilnya di-cache di browser.

Menambahkan beberapa string acak di QueryString tampaknya dapat mengatasi masalah ini (saya gunakan new Date().toString()), tetapi ini terasa seperti peretasan.

Apakah ada cara lain untuk mencapai ini? Atau, jika string unik adalah satu-satunya cara untuk mencapai ini, ada saran selain new Date()?

Salamander2007
sumber
Anda dapat menggunakan notasi singkat $.now()alih-alih melakukan (Tanggal baru (). GetTime ()) masing-masing dan setiap saat.
Dayson
1
Judul pertanyaan Anda agak menyesatkan. Bisakah Anda mempertimbangkan untuk mengganti nama?
0112
4
Sudahkah Anda mempertimbangkan untuk memilih jawaban lain sebagai jawaban yang diterima?
M4N

Jawaban:

241

Saya menggunakan new Date().getTime(), yang akan menghindari tabrakan kecuali jika Anda memiliki beberapa permintaan terjadi dalam milidetik yang sama:

$.get('/getdata?_=' + new Date().getTime(), function(data) {
    console.log(data); 
});

Sunting: Jawaban ini berumur beberapa tahun. Masih berfungsi (karenanya saya belum menghapusnya), tetapi ada cara yang lebih baik / lebih bersih untuk mencapai ini sekarang . Preferensi saya adalah untuk ini metode, tetapi ini jawabannya juga berguna jika Anda ingin caching menonaktifkan untuk setiap permintaan selama masa halaman.

Mark Bell
sumber
11
Saya akan downvote hanya karena lebih bersih untuk membiarkan jQuery melakukan ini seperti dalam jawaban oleh Peter J. Solusi Anda akan berhasil, tetapi lebih sulit untuk mempertahankannya dalam jangka panjang.
Niklas Wulff
11
Bagian mana dari ini yang membutuhkan perawatan? Jika dibandingkan dengan apa yang dilakukan jQuery?
Sunny R Gupta
5
Mungkin perlu dicatat bahwa new Date().getTime()kode digunakan seperti ini ... var nocache = new Date().getTime(); var path = 'http://hostname.domain.tld/api/somejsonapi/?cache=' + nocache;. Butuh beberapa menit untuk memikirkannya, sendiri. Tentu saja ?cachedapat berupa kata-kata yang sebenarnya tidak diinginkan oleh API.
doubleJ
1
1 bahkan jawaban Peter J memiliki pendekatan yang lebih baik. Jawaban ini tidak salah dan juga bukan jawaban yang buruk. Saya percaya bahwa DV dibuat karena milik Anda di atas Peter (seperti yang diterima). dan OP tidak muncul di SO sejak awal 2013
Michel Ayres
1
url = url + (-1 === url.indexOf('?') ? '?' : '&') + "__=" + Number(new Date());
514

Berikut ini akan mencegah semua permintaan AJAX di masa mendatang dari di-cache, terlepas dari metode jQuery yang Anda gunakan ($ .get, $ .ajax, dll.)

$.ajaxSetup({ cache: false });
Peter J
sumber
7
Setelah diselidiki (Fiddler), sepertinya jQuery mengimplementasikan ini secara internal dengan hanya menambahkan stempel waktu (seperti yang dibahas di tempat lain dalam jawaban ini). Bagi saya, metode .ajaxSetup lebih bersih (menurut saya.)
Peter J
8
Memang tidak perlu berada di dalam dokumen ready call.
Peter J
19
Mengapa menonaktifkan caching ajax secara global? Saya pikir itu harus dilakukan berdasarkan panggilan, seperti apa jawaban Jonathan.
Sunny R Gupta
5
Apa pun yang berfungsi untuk aplikasi Anda. Saya terus menggunakan metode ini dalam aplikasi komersial setiap kali saya benar-benar membutuhkan data segar untuk semua panggilan AJAX. Bagi yang lain, data dalam cache baik-baik saja.
Peter J
1
Deskripsi tautan : Tetapkan nilai default untuk permintaan Ajax di masa depan. Penggunaannya tidak disarankan.
itwebdeveloper
319

$ .Get () JQuery akan men-cache hasil. Dari pada

$.get("myurl", myCallback)

Anda harus menggunakan $ .ajax, yang memungkinkan Anda untuk mematikan caching:

$.ajax({url: "myurl", success: myCallback, cache: false});
Jonathan Moffatt
sumber
62
+1 Ini adalah jawaban yang benar. Solusi Peter J untuk menonaktifkan cache secara global adalah praktik buruk IMO.
Salman von Abbas
7
Penting untuk dicatat bahwa ini hanya "global" untuk halaman / permintaan.
Peter J
3
+1: Caching harus spesifik untuk jenis permintaan. Beberapa permintaan server mungkin perlu caching (di mana data server statis), jadi memilih caching berdasarkan permintaan berdasarkan permintaan lebih baik daripada hanya mematikannya .
Hilang Coding
1
+1 untuk jawaban yang benar - mencegah caching berdasarkan panggilan per menggunakan metode jQuery, bukan hack manual.
Bukit Brendan
2
Jawaban bagus lainnya. Saya harus mengatakan, bagi saya, sebagian besar waktu menonaktifkan cache secara global sangat bermanfaat. Itu semua tergantung pada bagaimana aplikasi Anda dirancang. Tidak ada peluru perak, tetapi dalam situasi ini, saya akan merekomendasikan fungsi yang menerima boolean untuk caching, fungsi untuk callback, dan URL untuk modularitas. Manual "hack" baik-baik saja, tetapi jika Anda menggunakan jQuery, tetap gunakan fungsinya jika memungkinkan. Ini tidak hanya akan membuat pengembangan lebih mudah sekarang, tetapi juga pemutakhiran ke perpustakaan di masa mendatang.
Anthony Mason
24

Semua jawaban di sini meninggalkan jejak pada URL yang diminta yang akan muncul di log akses server.

Saya membutuhkan solusi berbasis tajuk tanpa efek samping dan saya menemukan itu dapat dicapai dengan mengatur tajuk yang disebutkan dalam Cara mengontrol caching halaman web, di semua browser? .

Hasilnya, paling tidak berfungsi untuk Chrome, adalah:

$.ajax({
   url: url, 
   headers: {
     'Cache-Control': 'no-cache, no-store, must-revalidate', 
     'Pragma': 'no-cache', 
     'Expires': '0'
   }
});

Aidin
sumber
Mungkin pertanyaan bodoh, tetapi jika ajax saya mengembalikan gambar, apakah gambar akan di-cache? Untuk menghindari permintaan besar-besaran Amazon S3?
Marcelo Agimóvel
MarceloAgimóvel, itu bisa menjadi pertanyaan SO terpisah yang saya percaya.
Aidin
23

cara lain adalah dengan tidak menyediakan header cache dari server di dalam kode yang menghasilkan respons terhadap panggilan ajax:

response.setHeader( "Pragma", "no-cache" );
response.setHeader( "Cache-Control", "no-cache" );
response.setDateHeader( "Expires", 0 );
miceuz
sumber
17
Salah. Di IE, header no-cache diabaikan untuk panggilan XMLHttpRequest, seperti yang dibahas di sini: stackoverflow.com/questions/244918/... DateTime (atau metode .ajaxSetup saya) adalah satu-satunya solusi yang benar-benar berfungsi.
Peter J
Saya baru saja menyisipkan mantra cache yang biasa, tidak dinyatakan bahwa itu spesifik IE
miceuz
2
Ini harus mematikan caching untuk semua browser: response.setHeader ("Cache-Control", "max-age = 0, no-cache, no-store, post-check = 0, pre-check = 0");
Chris Broski
13

Secara pribadi saya merasa bahwa metode kueri string lebih dapat diandalkan daripada mencoba mengatur header di server - tidak ada jaminan bahwa proxy atau browser tidak akan hanya menyimpannya (beberapa browser lebih buruk daripada yang lain - tidak menyebutkan nama).

Saya biasanya menggunakan Math.random()tetapi saya tidak melihat ada yang salah dengan menggunakan tanggal (Anda seharusnya tidak melakukan permintaan AJAX cukup cepat untuk mendapatkan nilai yang sama dua kali).

Greg
sumber
2
Kombinasikan Date (). GetTime () bersama dengan Math.random () dan Anda harus berada di sisi yang aman. Di samping catatan, Ext.Ajax juga menggunakan getTime () ketika disableCaching ditentukan.
vividos
12

Berikut dokumentasi: http://api.jquery.com/jquery.ajax/

Anda dapat menggunakan cacheproperti dengan:

$.ajax({
    method: "GET",
    url: "/Home/AddProduct?",
    data: { param1: value1, param2: value2},
    cache: false,
    success: function (result) {
        // TODO
    }
});
MrMins
sumber
5

Tentu saja "pemecahan cache" teknik akan menyelesaikan pekerjaan, tetapi ini tidak akan terjadi di tempat pertama jika server menunjukkan kepada klien bahwa respons tidak boleh di-cache. Dalam beberapa kasus itu bermanfaat untuk tanggapan cache, beberapa kali tidak. Biarkan server memutuskan umur data yang benar. Anda mungkin ingin mengubahnya nanti. Jauh lebih mudah dilakukan dari server daripada dari berbagai tempat di kode UI Anda.

Tentu saja ini tidak membantu jika Anda tidak memiliki kendali atas server.

Mark Renouf
sumber
5

Bagaimana dengan menggunakan permintaan POST bukannya GET ...? (Yang seharusnya Anda tetap ...)

Thomas Hansen
sumber
Saya pikir itu solusi yang lebih baik, tetapi sayangnya saya (entah bagaimana) hanya dapat melakukan permintaan GET. Jadi .. ini Date (). GetTime () baru untuk saat ini.
Salamander2007
Silakan tambahkan beberapa penjelasan untuk jawaban Anda sehingga orang lain dapat belajar darinya - mengapa permintaan POST diperlukan?
Nico Haase
5

Pertanyaan sebenarnya adalah mengapa Anda perlu ini tidak di-cache. Jika tidak boleh di-cache karena itu berubah sepanjang waktu, server harus menentukan untuk tidak men-cache sumber daya. Jika kadang-kadang hanya berubah (karena salah satu sumber daya yang bergantung pada dapat berubah), dan jika kode klien memiliki cara untuk mengetahuinya, ia dapat menambahkan parameter dummy ke url yang dihitung dari beberapa hash atau tanggal modifikasi terakhir dari sumber daya tersebut (itulah yang kami lakukan dalam sumber daya skrip Microsoft Ajax sehingga mereka dapat di-cache selamanya tetapi versi baru masih dapat dilayani saat muncul). Jika klien tidak dapat mengetahui perubahan, cara yang benar seharusnya bagi server untuk menangani permintaan HEAD dengan benar dan memberi tahu klien apakah akan menggunakan versi yang di-cache atau tidak. Sepertinya saya suka menambahkan parameter acak atau mengatakan dari klien untuk tidak pernah cache salah karena cacheability adalah properti dari sumber daya server, dan karenanya harus diputuskan sisi server. Pertanyaan lain untuk ditanyakan kepada diri sendiri adalah apakah sumber ini harus benar-benar dilayani melalui GET atau haruskah melalui POST? Itu adalah pertanyaan tentang semantik, tetapi juga memiliki implikasi keamanan (ada serangan yang hanya berfungsi jika server mengizinkan GET). POST tidak akan di-cache.


sumber
6
Bagaimana jika Anda melalui server proxy yang tidak Anda kontrol kebijakan caching mereka? bagaimana jika aplikasi Anda secara eksplisit perlu melakukan permintaan baru setiap saat? Jawaban untuk hal-hal yang tidak selalu jelas dipotong hitam dan putih, selalu ada area abu-abu.
7wp
Benar, tidak selalu jelas. Tetapi melihat jawaban ini membuat saya mempertanyakan asumsi saya dan menuntun saya untuk menemukan akar penyebab masalah saya. Itu mungkin tidak berlaku untuk semua orang, tetapi itu membantu saya. Jika Anda di sini membaca ini, Anda harus mempertimbangkannya juga.
Jonathan Tran
Ini memang membantu saya, ResponseCaching diatur ke sisi server 60m secara default. Mengubahnya menjadi No-Cache dan menghentikan caching pada klien.
mattygee
4

Mungkin Anda harus melihat $ .ajax () sebagai gantinya (jika Anda menggunakan jQuery, yang terlihat seperti). Lihatlah: http://docs.jquery.com/Ajax/jQuery.ajax#options dan opsi "cache".

Pendekatan lain adalah dengan melihat bagaimana Anda menyimpan sesuatu di sisi server.

finpingvin
sumber
1
Sayangnya, setelah beberapa penyelidikan, menggunakan $ .ajax () dan mengatur cache = false pada dasarnya akan melakukan hal yang sama. jQuery akan menambahkan beberapa nomor acak ke querystring, dan itu tidak memeriksa querystring yang ada. Jadi saya kira menggunakan $ .get () akan cukup.
Salamander2007
Ah baiklah. Belum pernah mencobanya, baru ingat saya pernah melihat sesuatu tentang itu di dokumen :)
finpingvin
Bahkan tidak perlu menggunakan $ .ajax. Cukup gunakan .ajaxSetup.
Peter J
3

Tambahan kecil untuk jawaban luar biasa yang diberikan: Jika Anda menjalankan dengan solusi cadangan non-ajax untuk pengguna tanpa javascript, Anda harus tetap mendapatkan header sisi server yang benar. Ini bukan tidak mungkin, meskipun saya mengerti mereka yang menyerah;)

Saya yakin ada pertanyaan lain pada SO yang akan memberi Anda set lengkap header yang sesuai. Saya tidak sepenuhnya diyakinkan, jawaban tikus mencakup semua basis 100%.

krosenvold
sumber
3

Bagi Anda yang menggunakan cacheopsi $.ajaxSetup()pada Safari seluler, tampaknya Anda mungkin harus menggunakan cap waktu untuk POST, karena Safari seluler juga menyimpan cache. Menurut dokumentasi pada $.ajax()(dari mana Anda diarahkan $.ajaxSetup()):

Mengatur cache ke false hanya akan berfungsi dengan benar dengan permintaan HEAD dan GET. Ini bekerja dengan menambahkan "_ = {timestamp}" ke parameter GET. Parameter tidak diperlukan untuk jenis permintaan lainnya, kecuali di IE8 saat POST dibuat ke URL yang telah diminta oleh GET.

Jadi pengaturan opsi itu sendiri tidak akan membantu Anda dalam kasus yang saya sebutkan di atas.

Athasach
sumber
2

Pada dasarnya tambahkan saja cache:false;ajax di mana Anda pikir konten akan berubah seiring perkembangannya. Dan tempat di mana konten tidak akan berubah di sana kamu bisa menghilangkan ini. Dengan cara ini Anda akan mendapat respons baru setiap saat

Santosh Upadhayay
sumber
2

Sekarang, mudah untuk melakukannya dengan mengaktifkan / menonaktifkan opsi cache dalam permintaan ajax Anda, seperti ini

$(function () {
    var url = 'your url goes here';
    $('#ajaxButton').click(function (e) {
        $.ajax({
            url: url,
            data: {
                test: 'value'
            },
                cache: true, //cache enabled, false to reverse
                complete: doSomething
            });
        });
    });
    //ToDo after ajax call finishes
    function doSomething(data) {
        console.log(data);
    }
});
Omar El Don
sumber
3
Setelah 6 tahun Anda memberikan respons yang sama dengan Jonathan? ಠ_ಠ
redent84
orang dapat mengatakannya 6 tahun setelah pertanyaan diposting. Dan jawaban saya untuk pertanyaan itu berbeda dari yang lain, belum lagi itu yang benar saat ini. Menjawab pertanyaan semacam itu bukan untuk "penanya", melainkan untuk komunitas dan pemula! Terima kasih telah menambahkan klarifikasi!
Omar El Don
Dan apa perbedaan antara milik Anda dan yang ini stackoverflow.com/a/735084/469218 ?
redent84
mungkin kejelasan, dari sudut pandang seorang pemula yang mengajukan pertanyaan seperti itu !!
Omar El Don
1

Seperti yang dikatakan @Athasach, menurut jQuery docs, $.ajaxSetup({cache:false})tidak akan berfungsi untuk selain permintaan GET dan HEAD.

Anda lebih baik mengirim kembali Cache-Control: no-cachetajuk dari server Anda. Ini memberikan pemisahan keprihatinan yang lebih bersih.

Tentu saja, ini tidak akan berfungsi untuk url layanan yang bukan milik proyek Anda. Dalam hal ini, Anda dapat mempertimbangkan proksi layanan pihak ketiga dari kode server daripada memanggilnya dari kode klien.

rstackhouse
sumber
1

Jika Anda menggunakan .net ASP MVC, nonaktifkan caching pada tindakan pengontrol dengan menambahkan atribut berikut pada fungsi titik akhir:

[OutputCacheAttribute(VaryByParam = "*", Duration = 0, NoStore = true)]
Marius
sumber
Bisakah Anda jelaskan lebih lanjut? Bagaimana hubungan array itu dengan AJAX?
Nico Haase
Ini bukan sebuah array, ini adalah atribut pada Aksi Kontrol MVC.
Marius
0

tambahkan tajuk

headers: {
                'Cache-Control':'no-cache'
            }
Moaz Salem
sumber
Harap tambahkan beberapa penjelasan pada jawaban Anda sehingga orang lain dapat belajar darinya - di mana seharusnya header seperti itu ditambahkan?
Nico Haase
-3

tambahkan Math.random() ke url permintaan

Xiaoyifang
sumber
2
Ini akan memberikan hasil yang tidak stabil.
aj.toulan
Math.random hanya akan bertindak sebagai prameter, seperti url? _ = [Math.Random ()], itu tidak ada hubungannya dengan hasil yang tidak stabil.
xiaoyifang
4
Saya mengerti apa yang Anda lakukan. Saya hanya berkomentar bahwa Math.Random () terkadang akan memberi Anda nomor yang sama dua kali. Jika Anda mengisi sistem Anda dengan ketidakpastian, mereka hanya akan menambah satu sama lain.
aj.toulan