วิธีป้องกันการแคชหน้าเบราว์เซอร์ใน Rails


151

Ubuntu -> Apache -> Phusion Passenger -> Rails 2.3

ส่วนหลักของเว็บไซต์ของฉันตอบสนองต่อการคลิกของคุณ ดังนั้นหากคุณคลิกที่ลิงค์มันจะส่งคุณไปยังปลายทางและสร้างหน้าเว็บของคุณใหม่ทันที

แต่ถ้าคุณกดปุ่มย้อนกลับคุณจะไม่เห็นหน้าใหม่ น่าเสียดายที่มันไม่ปรากฏขึ้นหากไม่มีการรีเฟรชด้วยตนเอง ปรากฏว่าเบราว์เซอร์กำลังแคชอยู่ ฉันต้องการตรวจสอบให้แน่ใจว่าเบราว์เซอร์ไม่ได้แคชหน้า

แยกกันผมไม่ต้องการที่จะกำหนดวันหมดอายุไกลในอนาคตสำหรับสินทรัพย์คงที่ของฉันทั้งหมด

วิธีที่ดีที่สุดในการแก้ปัญหานี้คืออะไร ฉันควรแก้ปัญหานี้ใน Rails หรือไม่? Apache? Javascript?

ขอบคุณสำหรับความช่วยเหลือของคุณ Jason


อนิจจา. ข้อเสนอแนะเหล่านี้ไม่ได้บังคับพฤติกรรมที่ฉันกำลังมองหา

อาจจะมีคำตอบจาวาสคริปต์? ฉันสามารถมีทางรถไฟเขียนบันทึกเวลาในความคิดเห็นแล้วมีจาวาสคริปต์ตรวจสอบเพื่อดูว่าเวลาภายในห้าวินาที (หรืออะไรก็ได้) ถ้าใช่ก็ไม่เป็นไร แต่ถ้าไม่ใช่จากนั้นโหลดหน้าซ้ำหรือไม่

คุณคิดว่าจะใช้การได้หรือไม่

ขอบคุณสำหรับความช่วยเหลือของคุณ

เจสัน

คำตอบ:


335

ในที่สุดคิดออกนี้ - http://blog.serendeputy.com/posts/how-to-prevent-browsers-from-caching-a-page-in-rails/ในapplication_controller.rb

หลังจากรางที่ 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 และเวอร์ชั่นที่เก่ากว่า:

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

3
สิ่งนี้ควรถูกห่อด้วย "ถ้า request.xhr?" ดังนั้นจะได้รับการตั้งค่าบน Ajax รีเฟรช แต่หน้าปกติไม่ได้?
MintDeparture

3
คุณต้องการเพียงCache-Control: no-storeตราบเท่าที่เบราว์เซอร์สอดคล้องกับ HTTP 1.1 ส่วนที่ 14.9.2 แคชอาจเก็บอะไรได้บ้าง
gaqzi

28
1 มกราคม 1990 เป็นวันจันทร์!
Jan Hettich

2
มันไม่ทำงานสำหรับฉันฉันได้เพิ่มรหัสเดียวกันใน application_controller.rb และหลังจากออกจากระบบฉันสามารถดูหน้าสุดท้ายโดยปุ่มย้อนกลับ กรุณาแนะนำฉันที่ฉันผิด
Thorin

1
สิ่งนี้จะไม่แคช JS และ CSS ในแอปพลิเคชันทางรถไฟหรือไม่ JS และ CSS จะโหลดจากเซิร์ฟเวอร์สำหรับแต่ละคำขอหรือไม่
furiabhavesh

14

3
expires_nowส่งno-cacheส่วนหัวเท่านั้น ขึ้นอยู่กับเบราว์เซอร์ซึ่งอาจไม่เพียงพอ (ตัวอย่างเช่น Firefox ต้องการการno-storeเชื่อมต่อที่ไม่ใช่ HTTPS: developer.mozilla.org/en/docs/Using_Firefox_1.5_caching )
Daniel Rikowski

1
ตกลงนี้ไม่ได้เป็นวิธีการแก้ปัญหาที่ถูกต้องทดสอบกับ Rails 5.2 และ Chrome 77 no-storeยังเป็นสิ่งจำเป็น
AndrewSouthpaw

3

ฉันใช้บรรทัดนี้กับความสำเร็จในคอนโทรลเลอร์ มันทำงานได้ใน Safari และ Internet Explorer แต่ฉันไม่เห็นมันทำงานกับ Firefox

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

สำหรับจุดที่สองของคุณหากคุณใช้วิธีการของตัวช่วยรางเช่น

stylesheet_link_tag

และปล่อยให้การตั้งค่าเริ่มต้นในเว็บเซิร์ฟเวอร์ของคุณโดยทั่วไปสินทรัพย์จะถูกแคชค่อนข้างดี


3
1.year.agoเป็นค่าใช้จ่ายที่ไม่จำเป็น เพียงเลือกเวลาโดยพลการในอดีตอย่างเช่นFri, 01 Jan 1990 00:00:00 GMT
Archonic

6
@Archonic 1 มกราคม 1990 เป็นวันจันทร์!
Thomas R. Koll

1

วิธีที่สะอาดกว่าคือเขียนมิดเดิลแวร์ของ Rack ซึ่งเปลี่ยนส่วนหัวของ Cache-Control ตามลอจิกบางอย่าง (ตัวอย่างเช่นสำหรับแอ็พพลิเคชัน / xml mime-type เท่านั้น) หรือสำหรับ uglier แต่ยังคงใช้งานได้เราสามารถเปลี่ยนค่าคงที่ของ ActionDispatch :: Response :: DEFAULT_CACHE_CONTROL เป็น 'no-cache' แน่นอนว่าถ้าจำเป็นต้องใช้ตัวควบคุมและ / หรือการกระทำที่ละเอียดยิ่งกว่านั้นให้ทำเช่นนี้ในคอนโทรลเลอร์


1

จุดที่ควรทราบ: คุณไม่สามารถล้างแคชแบบมีเงื่อนไข (เช่นถ้ามีการbefore_filterโทรเฉพาะreset_cacheเมื่อผู้ใช้อยู่ที่นั่นแล้ว) คุณต้องล้างแคชโดยไม่มีเงื่อนไขเนื่องจากเบราว์เซอร์จะไม่ส่งคำขอใหม่เพื่อดูว่าครั้งนี้จะต้องโหลดซ้ำหรือไม่แม้ว่าจะไม่จำเป็นต้องใช้ครั้งล่าสุด

ตัวอย่าง:

before_filter :reset_cache, if: :user_completed_demographics?

จะไม่ทำงานเพื่อป้องกันไม่ให้ผู้ใช้กลับมาหลังจากพวกเขาอยู่ที่นั่นเนื่องจากเบราว์เซอร์ใช้ส่วนหัวแคชดั้งเดิมบนปุ่มย้อนกลับ

before_filter :reset_cache

จะทำงานอย่างไร (หลังจากรีเฟรชหน้าและล้างแคชจากก่อนที่คุณจะเพิ่มสิ่งนี้อย่างชัดเจน) เนื่องจากในคำขอแรกเบราว์เซอร์จะได้รับno-cache, no-store, ...และนำไปใช้กับการโหลดหน้าเว็บในอนาคต


0

no_cache_control อัญมณี.

หากคุณต้องการทำสิ่งนี้สำหรับการตอบกลับทั้งหมดเช่นผ่านการทดสอบการเจาะ (BURP, Detectify เป็นต้น) คุณสามารถติดตั้ง Gem นี้บน Rails 4+ เพื่อเพิ่มหัวข้อต่อไปนี้ลงในการตอบกลับทั้งหมด:

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

ใช้งานได้อย่างมีเสน่ห์และเป็นวิธีที่เหมาะสมในการใช้งานเว็บแอปพลิเคชัน HTTPS ที่ปลอดภัยซึ่งต้องมีการตรวจสอบสิทธิ์เพื่อทำสิ่งใด ๆ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.