Bagaimana mencegah caching halaman browser di Rails

151

Ubuntu -> Apache -> Penumpang Phusion -> Rails 2.3

Bagian utama situs saya bereaksi terhadap klik Anda. Jadi, jika Anda mengeklik tautan, tautan itu akan mengirim Anda ke tujuan, dan segera membuat kembali halaman Anda.

Tetapi, jika Anda menekan tombol kembali, Anda tidak melihat halaman baru. Sayangnya, itu tidak muncul tanpa penyegaran manual; tampaknya browser sedang menyimpannya. Saya ingin memastikan browser tidak men-cache halaman.

Secara terpisah, saya tidak ingin mengatur tanggal kadaluarsa jauh-masa depan untuk semua aset statis saya.

Apa cara terbaik untuk menyelesaikan ini? Haruskah saya menyelesaikan ini di Rails? Apache? Javascript?

Terima kasih atas semua bantuan Anda, Jason


Sayang. Tidak satu pun dari saran ini yang memaksa perilaku yang saya cari.

Mungkin ada jawaban javascript? Saya bisa meminta rails menuliskan stempel waktu dalam komentar, kemudian periksa javascript untuk melihat apakah waktunya dalam lima detik (atau apa pun yang berfungsi). Jika ya, baik-baik saja, tetapi jika tidak, muat ulang halaman?

Apakah Anda pikir ini akan berhasil?

Terima kasih atas seluruh bantuan Anda,

Jason

Jason Butler
sumber

Jawaban:

335

Akhirnya menemukan ini - http://blog.serendeputy.com/posts/how-to-prevent-browsers-dari-caching-a-page-in-rails/ diapplication_controller.rb

Setelah Rel 5:

class ApplicationController < ActionController::Base

  before_action :set_cache_headers

  private

  def set_cache_headers
    response.headers["Cache-Control"] = "no-cache, no-store"
    response.headers["Pragma"] = "no-cache"
    response.headers["Expires"] = "Mon, 01 Jan 1990 00:00:00 GMT"
  end
end

Rails 4 dan versi yang lebih lama:

class ApplicationController < ActionController::Base

  before_filter :set_cache_headers

  private

  def set_cache_headers
    response.headers["Cache-Control"] = "no-cache, no-store"
    response.headers["Pragma"] = "no-cache"
    response.headers["Expires"] = "Mon, 01 Jan 1990 00:00:00 GMT"
  end
end
Jason Butler
sumber
3
Haruskah ini dibungkus dengan "jika request.xhr?" jadi itu hanya akan diatur pada refresh ajax tetapi halaman normal tidak?
MintDeparture
3
Anda hanya perlu Cache-Control: no-storeselama peramban ini sesuai dengan HTTP 1.1. Bagian 14.9.2 Apa yang Mungkin Disimpan oleh
Tembolok
28
1 Jan 1990, adalah hari Senin!
Jan Hettich
2
Ini tidak berfungsi untuk saya, saya telah menambahkan kode yang sama di application_controller.rb dan setelah logout saya bisa melihat halaman terakhir dengan tombol kembali. Tolong tuntun saya di mana saya salah?
Thorin
1
Apakah ini juga TIDAK akan menyimpan cache JS dan CSS di app rails? Apakah JS dan CSS akan dimuat dari server untuk setiap permintaan?
furiabhavesh
14

menggunakan:

expires_now()

http://api.rubyonrails.org/classes/ActionController/ConditionalGet.html#method-i-expires_now

Sacre
sumber
3
expires_nowhanya mengirim no-cachetajuk. Tergantung pada browser ini mungkin tidak cukup. (Misalnya Firefox menginginkan no-storekoneksi non-HTTPS: developer.mozilla.org/en/docs/Using_Firefox_1.5_caching )
Daniel Rikowski
1
Setuju, ini bukan solusi yang valid, diuji dengan Rails 5.2 dan Chrome 77. no-storejuga diperlukan.
AndrewSouthpaw
3

Saya telah menggunakan baris ini dengan beberapa keberhasilan di controller. Ini bekerja di Safari dan Internet Explorer tetapi saya belum melihatnya bekerja dengan Firefox.

response.headers["Expires"] = "#{1.year.ago}"

Untuk poin kedua Anda, jika Anda menggunakan metode pembantu rel seperti

stylesheet_link_tag

dan biarkan pengaturan default di server web Anda, aset biasanya di-cache cukup baik.

erik
sumber
3
1.year.agoadalah overhead yang tidak perlu. Fri, 01 Jan 1990 00:00:00 GMT
Pilih
6
@Archonic 1 Januari 1990 adalah hari Senin!
Thomas R. Koll
1

Cara bersih adalah dengan menulis middleware Rack, yang mengubah header Cache-Control berdasarkan pada beberapa logika (misalnya, hanya untuk aplikasi / tipe mime xml). Atau, untuk pendekatan yang lebih buruk, tetapi masih berfungsi, seseorang dapat mengubah ActionDispatch :: Response :: DEFAULT_CACHE_CONTROL konstan menjadi 'no-cache'. Tentu saja, jika granularity controller dan / atau action diperlukan, maka lebih baik melakukannya di controller.

Roma
sumber
1

Catatan: Anda tidak dapat menghapus cache secara kondisional (seperti jika before_filterhanya memanggil reset_cachejika pengguna sudah ada di sana). Anda perlu menghapus cache tanpa syarat , karena browser tidak akan membuat permintaan baru hanya untuk melihat apakah kali ini, perlu memuat ulang, meskipun itu tidak perlu terakhir kali.

Contoh:

before_filter :reset_cache, if: :user_completed_demographics?

tidak akan berfungsi untuk mencegah pengguna kembali setelah mereka berada di sana, karena browser menggunakan header cache asli pada tombol Kembali.

before_filter :reset_cache

akan bekerja, namun (setelah me-refresh halaman dan membersihkan cache dari sebelum Anda menambahkan ini, jelas), karena, pada permintaan pertama, browser akan mendapatkan no-cache, no-store, ...dan menerapkannya untuk memuat halaman berikutnya.

BalinKingOfMoria Reinstate CMs
sumber
0

no_cache_control Permata

Jika Anda perlu melakukan ini untuk semua respons, misalnya untuk lulus tes penetrasi (BURP, Detectify, dll.), Anda dapat menginstal Permata ini di Rails 4+ untuk menambahkan header berikut ke semua respons:

Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: -1

Bekerja seperti pesona dan benar-benar cara yang tepat untuk aplikasi web HTTPS yang aman dan memerlukan otentikasi untuk melakukan apa saja.

Joshua Pinter
sumber