วิธีบังคับไม่ให้เว็บเบราว์เซอร์แคชรูปภาพ


124

พื้นหลัง

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

ปัญหา

ปัญหาเกิดขึ้นเมื่อผู้ดูแลระบบต้องการเปลี่ยนรูปภาพ เขาจะต้องกดปุ่ม "เรียกดู" เลือกภาพใหม่แล้วกดตกลง และใช้งานได้ดี

เมื่ออัปโหลดภาพแล้ว CGI ส่วนหลังของฉันจะจัดการการอัปโหลดและโหลดแบบฟอร์มซ้ำอย่างเหมาะสม

ปัญหาคือรูปภาพที่แสดงไม่ได้รับการรีเฟรช ภาพเก่ายังคงแสดงแม้ว่าฐานข้อมูลจะเก็บภาพที่ถูกต้อง ฉันได้ จำกัด ขอบเขตให้แคบลงตามข้อเท็จจริงที่ว่ารูปภาพถูกแคชในเว็บเบราว์เซอร์ หากผู้ดูแลระบบกดปุ่ม RELOAD ใน Firefox / Explorer / Safari ทุกอย่างจะได้รับการรีเฟรชตามปกติและรูปภาพใหม่จะปรากฏขึ้น

โซลูชันของฉัน - ไม่ทำงาน

ฉันพยายามควบคุมแคชโดยเขียนคำสั่ง HTTP Expires พร้อมวันที่ที่ผ่านมา

Expires: Mon, 15 Sep 2003 1:00:00 GMT

โปรดจำไว้ว่าฉันอยู่ในด้านการดูแลระบบและฉันไม่สนใจจริงๆว่าหน้าจะใช้เวลาโหลดนานกว่านี้เล็กน้อยหรือไม่เพราะหน้าเหล่านี้จะหมดอายุเสมอ

แต่ก็ไม่ได้ผลเช่นกัน

หมายเหตุ

เมื่ออัปโหลดภาพชื่อไฟล์จะไม่ถูกเก็บไว้ในฐานข้อมูล เปลี่ยนชื่อเป็นImage.jpg (เป็นเพียงสิ่งเดียวเมื่อใช้มัน) เมื่อแทนที่ภาพที่มีอยู่ด้วยภาพใหม่ชื่อจะไม่เปลี่ยนเช่นกัน เพียงแค่เนื้อหาของไฟล์ภาพเปลี่ยนไป

เว็บเซิร์ฟเวอร์ให้บริการโดยบริการโฮสต์ / ISP ใช้ Apache

คำถาม

มีวิธีบังคับให้เว็บเบราว์เซอร์ไม่แคชสิ่งต่างๆจากหน้านี้หรือไม่แม้แต่รูปภาพ

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


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

คำตอบ:


186

Armin Ronacher มีความคิดที่ถูกต้อง ปัญหาคือสตริงสุ่มสามารถชนกันได้ ฉันจะใช้:

<img src="picture.jpg?1222259157.415" alt="">

โดยที่ "1222259157.415" คือเวลาปัจจุบันบนเซิร์ฟเวอร์
สร้างเวลาโดย Javascript ด้วยperformance.now()หรือโดย Python ด้วยtime.time()


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

8
โจเอลคุณน่าจะดีกว่าที่จะเพิ่มคำตอบของคุณเอง
epochwolf

1
เป็นเพียงความคิดและสายเกินไปที่จะมางานปาร์ตี้ที่นี่ - แต่เนื่องจากคุณสามารถควบคุมการเปลี่ยนรูปภาพได้บางทีอาจจะเป็นการดีกว่าที่จะเปลี่ยนชื่อรูปภาพเมื่อมีการอัปเดตแทนที่จะเพิ่มสตริงข้อความค้นหา ดังนั้น: 1222259157.jpg เช่นแทนที่จะเป็น picture.jpg? 1222259157 ด้วยวิธีนี้จะได้รับการอัปเดตและแคชอีกครั้งเมื่อเข้าชมอีกครั้ง
danjah

43
แทนที่จะเพิ่มเวลาเซิร์ฟเวอร์ซึ่งจะป้องกันการแคชไปพร้อมกันทำไมไม่เพิ่มเวลาที่แก้ไขล่าสุดของไฟล์หลังจาก "?" ด้วยวิธีนี้ภาพจะถูกแคชตามปกติจนกว่าจะมีการเปลี่ยนแปลงครั้งต่อไป
Doin

3
ความคิดเห็นสุดท้ายโดย Doin ต้องได้รับการโหวต! การแคชสมาร์ทมีความสำคัญจริง ๆ เหตุใดบางคนจึงต้องดาวน์โหลดไฟล์ซ้ำแล้วซ้ำอีก
f.arcarese

46

แก้ไขอย่างง่าย: แนบสตริงแบบสอบถามแบบสุ่มเข้ากับรูปภาพ:

<img src="foo.cgi?random=323527528432525.24234" alt="">

HTTP RFC พูดว่าอย่างไร:

Cache-Control: no-cache

แต่ก็ไม่ได้ผลดี :)


1
วิธีให้ Cache-Control: no-cache ในแท็ก html <img> ปกติ
P Satish Patro

จำเป็นต้องมาในส่วนหัวการตอบกลับหรือไม่?
P Satish Patro

22

ฉันใช้ฟังก์ชันเวลาแก้ไขไฟล์ของ PHPตัวอย่างเช่น:

echo <img  src='Images/image.png?" . filemtime('Images/image.png') . "'  />";

หากคุณเปลี่ยนรูปภาพระบบจะใช้รูปภาพใหม่แทนรูปภาพที่แคชเนื่องจากมีการประทับเวลาที่แก้ไขแตกต่างกัน


เคล็ดลับที่ดี คุณมีทั้งแคชและรูปภาพที่ส่งซ้ำไปยังไคลเอนต์หากเวลาที่แก้ไขเปลี่ยนแปลงไป (เขียนทับหรือเปลี่ยนแปลง)
Vasilis Lourdas

ดูตัวเลือกอื่นได้ที่นี่stackoverflow.com/questions/56588850/…
drooh

แน่นอนตอกมัน เพื่อนร่วมทิปที่ดี
Khurram Shaikh

สมบูรณ์แบบ! เคล็ดลับเพิ่มเติม: <img src = "images / image.png? <? php echo filemtime ('images / image.jpg')?>">
Rica Gurgel

16

ฉันจะใช้:

<img src="picture.jpg?20130910043254">

โดยที่ "20130910043254" คือเวลาแก้ไขไฟล์

เมื่ออัปโหลดภาพชื่อไฟล์จะไม่ถูกเก็บไว้ในฐานข้อมูล มันถูกเปลี่ยนชื่อเป็น Image.jpg (เป็นเพียงสิ่งเดียวเมื่อใช้มัน) เมื่อแทนที่ภาพที่มีอยู่ด้วยภาพใหม่ชื่อจะไม่เปลี่ยนเช่นกัน เพียงแค่เนื้อหาของไฟล์ภาพเปลี่ยนไป

ฉันคิดว่าวิธีแก้ปัญหาง่ายๆมีอยู่สองประเภท: 1) วิธีแก้ปัญหาที่ต้องคำนึงถึงก่อน (วิธีแก้ปัญหาที่ตรงไปตรงมาเพราะเกิดขึ้นได้ง่าย) 2) วิธีแก้ปัญหาที่คุณจบลงหลังจากคิดสิ่งต่างๆแล้ว (เพราะง่ายต่อการ ใช้). เห็นได้ชัดว่าคุณจะไม่ได้รับประโยชน์เสมอไปหากคุณเลือกที่จะคิดเรื่องต่างๆ แต่ตัวเลือกที่สองค่อนข้างถูกประเมินต่ำเกินไปฉันเชื่อว่า แค่คิดว่าทำไมถึงphpเป็นที่นิยม;)


1
+1 ฉันคิดว่ามันเป็นความคิดที่ดีกว่าคำตอบอื่น ๆ เนื่องจากเมื่อใช้เวลาในการปรับเปลี่ยน las เซิร์ฟเวอร์ของคุณจะไม่พยายามให้ภาพเดียวกันหลาย ๆ ครั้งกับเบราว์เซอร์เดียวกันเมื่อไม่มีอะไรเปลี่ยนแปลงในภาพ มีค่าใช้จ่ายเล็กน้อยในการดึงเวลาเขียนครั้งสุดท้ายของรูปภาพทุกครั้งที่มีการร้องขอ แต่สำหรับภาพขนาดใหญ่จะดีกว่าที่จะต้องส่งคืนรูปภาพในแต่ละครั้งและเมื่อรูปภาพเปลี่ยนไปผู้ใช้จะมีใหม่ ขอบคุณสำหรับการเพิ่มเล็กน้อยที่ดีนี้
Samuel

เราอาจจัดเก็บเวลาแก้ไขพร้อมกับพา ธ ไปยังรูปภาพในฐานข้อมูล ดังนั้นค่าใช้จ่ายอาจมีความสำคัญน้อยกว่าด้วยซ้ำ ในทางกลับกันหากเป็นภาพที่เป็นส่วนหนึ่งของซอร์สโค้ดที่เรากำลังพูดถึงอาจมีการแคชเวลาแก้ไขด้วย โดยการสร้างสคริปต์ที่มีการปรับเปลี่ยนเวลาของภาพ (เช่นimages.php) สคริปต์นี้จะต้องสร้างขึ้นใหม่ในแต่ละคอมมิตและกำจัดค่าใช้จ่ายในการกำหนดเวลาแก้ไขไฟล์
x-yuri

@ x-yori นี่คือเหตุผลที่ฉันเลือกที่จะเก็บฟิลด์ที่อัปเดตนี้ไว้ในฐานข้อมูลแทนที่จะเรียกใช้ filemtime stackoverflow.com/questions/56588850/…
drooh

9

ใช้Class = "NO-CACHE"

html ตัวอย่าง:

<div>
    <img class="NO-CACHE" src="images/img1.jpg" />
    <img class="NO-CACHE" src="images/imgLogo.jpg" />
</div>

jQuery:

    $(document).ready(function ()
    {           
        $('.NO-CACHE').attr('src',function () { return $(this).attr('src') + "?a=" + Math.random() });
    });

javascript:

var nods = document.getElementsByClassName('NO-CACHE');
for (var i = 0; i < nods.length; i++)
{
    nods[i].attributes['src'].value += "?a=" + Math.random();
}

ผลลัพธ์: src = "images / img1.jpg" => src = "images / img1.jpg? a = 0.08749723793963926"


เรียบง่ายหรูหราและไม่ต้องการการแสดงผลฝั่งเซิร์ฟเวอร์ NICE!
Ahi Tuna

7

คุณสามารถเขียนสคริปต์พร็อกซีสำหรับการแสดงภาพซึ่งเป็นวิธีที่ดีกว่าเล็กน้อย สิ่งนี้ชอบ:

HTML:

<img src="image.php?img=imageFile.jpg&some-random-number-262376" />

สคริปต์:

// PHP
if( isset( $_GET['img'] ) && is_file( IMG_PATH . $_GET['img'] ) ) {

  // read contents
  $f = open( IMG_PATH . $_GET['img'] );
  $img = $f.read();
  $f.close();

  // no-cache headers - complete set
  // these copied from [php.net/header][1], tested myself - works
  header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Some time in the past
  header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); 
  header("Cache-Control: no-store, no-cache, must-revalidate"); 
  header("Cache-Control: post-check=0, pre-check=0", false); 
  header("Pragma: no-cache"); 

  // image related headers
  header('Accept-Ranges: bytes');
  header('Content-Length: '.strlen( $img )); // How many bytes we're going to send
  header('Content-Type: image/jpeg'); // or image/png etc

  // actual image
  echo $img;
  exit();
}

จริงๆแล้วส่วนหัวที่ไม่มีแคชหรือหมายเลขสุ่มที่ image src ก็น่าจะเพียงพอแล้ว แต่เนื่องจากเราต้องการเป็นสัญลักษณ์แสดงหัวข้อย่อย ..


คุณเป็นทางออกที่ดียกเว้นว่า Pragma ไม่ใช่ส่วนหัวการตอบกลับ
Piskvor ออกจากอาคาร

1
@Piskvor: w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.32ดูเหมือนจะพูดเป็นอย่างอื่น
Grizly

6

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

<meta Http-Equiv="Cache" content="no-cache">
<meta Http-Equiv="Pragma-Control" content="no-cache">
<meta Http-Equiv="Cache-directive" Content="no-cache">
<meta Http-Equiv="Pragma-directive" Content="no-cache">
<meta Http-Equiv="Cache-Control" Content="no-cache">
<meta Http-Equiv="Pragma" Content="no-cache">
<meta Http-Equiv="Expires" Content="0">
<meta Http-Equiv="Pragma-directive: no-cache">
<meta Http-Equiv="Cache-directive: no-cache">

ไม่แน่ใจว่าอะไรใช้งานได้บนเบราว์เซอร์ใด แต่ใช้ได้กับบางตัว: IE: ใช้งานได้เมื่อมีการรีเฟรชหน้าเว็บและเมื่อมีการเยี่ยมชมเว็บไซต์อีกครั้ง (โดยไม่ต้องรีเฟรช) CHROME: ใช้งานได้เฉพาะเมื่อมีการรีเฟรชหน้าเว็บ (แม้จะมีการเข้าชมอีกครั้ง) SAFARI และ iPad: ใช้ไม่ได้ฉันต้องล้างประวัติและข้อมูลเว็บ

ความคิดใด ๆ เกี่ยวกับ SAFARI / iPad?


4

เมื่ออัปโหลดภาพชื่อไฟล์จะไม่ถูกเก็บไว้ในฐานข้อมูล มันถูกเปลี่ยนชื่อเป็น Image.jpg (เป็นเพียงสิ่งเดียวเมื่อใช้มัน)

เปลี่ยนสิ่งนี้และคุณได้แก้ไขปัญหาของคุณแล้ว ฉันใช้การประทับเวลาเช่นเดียวกับโซลูชันที่เสนอข้างต้น: Image- <timestamp> .jpg

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


4

ฉันตรวจสอบคำตอบทั้งหมดในเว็บและคำตอบที่ดีที่สุดดูเหมือนจะเป็น: (จริงๆแล้วไม่ใช่)

<img src="image.png?cache=none">

ในตอนแรก.

อย่างไรก็ตามหากคุณเพิ่มพารามิเตอร์cache = none (ซึ่งเป็นคำว่า "ไม่มี" แบบคงที่) จะไม่ส่งผลใด ๆ เบราว์เซอร์ยังคงโหลดจากแคช

วิธีแก้ไขปัญหานี้คือ:

<img src="image.png?nocache=<?php echo time(); ?>">

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

อย่างไรก็ตามปัญหาของฉันแตกต่างกันเล็กน้อย: ฉันกำลังโหลดรูปภาพแผนภูมิ php ที่สร้างขึ้นในทันทีและควบคุมเพจด้วยพารามิเตอร์ $ _GET ฉันต้องการให้อ่านรูปภาพจากแคชเมื่อพารามิเตอร์ URL GET ยังคงเหมือนเดิมและไม่แคชเมื่อพารามิเตอร์ GET เปลี่ยนไป

ในการแก้ปัญหานี้ฉันต้องแฮช $ _GET แต่เนื่องจากเป็นอาร์เรย์นี่คือวิธีแก้ปัญหา:

$chart_hash = md5(implode('-', $_GET));
echo "<img src='/images/mychart.png?hash=$chart_hash'>";

แก้ไข :

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

echo "<img src='/images/mychart.png?hash=" . filemtime('mychart.png') . "'>";

filemtime () ได้รับเวลาแก้ไขไฟล์


2
filemtimeวิธีการแก้ปัญหาจะดีกว่าเพราะmd5ใช้เวลามากของพลังการประมวลผล
oriadam

2
ใช้เวลาหลายวันในการรับแอปที่ใช้ Chromium เพื่อหยุดการแคชรูปภาพ nocache กับ time echo ช่วยแก้ปัญหาได้ ขอบคุณ!
Woody

2

ปัญหาของคุณคือแม้จะมีExpires:ส่วนหัว แต่เบราว์เซอร์ของคุณก็กลับมาใช้สำเนาของภาพในหน่วยความจำก่อนที่จะอัปเดตแทนที่จะตรวจสอบแคช

ฉันมีสถานการณ์ที่คล้ายกันมากในการอัปโหลดรูปภาพผลิตภัณฑ์ในแบ็กเอนด์ผู้ดูแลระบบสำหรับไซต์ที่มีลักษณะเหมือนร้านค้าและในกรณีของฉันฉันตัดสินใจว่าตัวเลือกที่ดีที่สุดคือใช้จาวาสคริปต์เพื่อบังคับให้รีเฟรชรูปภาพโดยไม่ต้องใช้เทคนิคการแก้ไข URL ใด ๆ ของคนอื่น ได้กล่าวไว้แล้วที่นี่ แต่ฉันใส่ URL ของรูปภาพลงใน IFRAME ที่ซ่อนอยู่ซึ่งเรียกว่าlocation.reload(true)บนหน้าต่างของ IFRAME จากนั้นแทนที่รูปภาพของฉันบนเพจ สิ่งนี้บังคับให้มีการรีเฟรชรูปภาพไม่ใช่แค่บนหน้าที่ฉันเปิดอยู่เท่านั้น แต่ยังรวมถึงเพจอื่น ๆ ที่ฉันเข้าชมอีกด้วยโดยที่ไคลเอนต์หรือเซิร์ฟเวอร์ไม่ต้องจำสตริงคิวรี URL หรือพารามิเตอร์ตัวระบุแฟรกเมนต์

ผมโพสต์รหัสบางอย่างที่จะทำเช่นนี้ในคำตอบของฉันที่นี่


2

เพิ่มการประทับเวลา <img src="picture.jpg?t=<?php echo time();?>">

จะให้หมายเลขสุ่มในตอนท้ายเสมอและหยุดการแคช


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

1

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

หากการประทับเวลานั้นตรงกับเวลาอัปเดตล่าสุดของรูปภาพคุณสามารถแคชเมื่อต้องการและแสดงภาพใหม่ในเวลาที่เหมาะสม


1

ฉันถือว่าคำถามเดิมเกี่ยวกับรูปภาพที่จัดเก็บพร้อมข้อมูลข้อความบางส่วน ดังนั้นหากคุณสามารถเข้าถึงบริบทข้อความเมื่อสร้าง src = ... url ให้พิจารณาจัดเก็บ / ใช้ CRC32 ของไบต์รูปภาพแทนการสุ่มหรือการประทับเวลาที่ไม่มีความหมาย จากนั้นหากแสดงหน้าที่มีรูปภาพจำนวนมากระบบจะโหลดเฉพาะรูปภาพที่อัปเดตเท่านั้น ในที่สุดถ้าการจัดเก็บ CRC เป็นไปไม่ได้ก็สามารถคำนวณและต่อท้าย url ที่รันไทม์ได้


หรือใช้เวลาที่แก้ไขล่าสุดของภาพแทน CRC ยิ่งดีไปอีก!
Doin

1

จากมุมมองของฉันการปิดใช้งานการแคชรูปภาพเป็นความคิดที่ไม่ดี เลย.

ปัญหาหลักที่นี่คือ - วิธีบังคับให้เบราว์เซอร์อัปเดตอิมเมจเมื่ออัปเดตบนฝั่งเซิร์ฟเวอร์แล้ว

อีกครั้งจากมุมมองส่วนตัวของฉันทางออกที่ดีที่สุดคือปิดการเข้าถึงภาพโดยตรง เข้าถึงรูปภาพผ่านตัวกรองฝั่งเซิร์ฟเวอร์ / servlet / เครื่องมือ / บริการอื่น ๆ ที่คล้ายคลึงกันแทน

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

ข้อยกเว้นเพียงอย่างเดียวคือ Favicons ด้วยเหตุผลบางประการมันไม่ได้ผล ฉันไม่สามารถบังคับให้เบราว์เซอร์อัปเดตแคชจากฝั่งเซิร์ฟเวอร์ได้ ETags, Cache Control, Expires, Pragma headers ไม่มีอะไรช่วย

ในกรณีนี้ดูเหมือนว่าการเพิ่มพารามิเตอร์ random / version ลงใน url จะเป็นทางออกเดียว


1

ตามหลักการแล้วคุณควรเพิ่มปุ่ม / การผูกแป้น / เมนูให้กับแต่ละหน้าเว็บพร้อมตัวเลือกในการซิงโครไนซ์เนื้อหา

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

ตัวอย่างที่ไร้เดียงสามีลักษณะดังนี้:

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

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

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="mobile-web-app-capable" content="yes" />        
    <title>Resource Synchronization Test</title>
    <script>
function sync() {
    var xhr = new XMLHttpRequest;
    xhr.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {            
            var images = document.getElementsByClassName("depends-on-resource");

            for (var i = 0; i < images.length; ++i) {
                var image = images[i];
                if (image.getAttribute('data-resource-name') == 'resource.bmp') {
                    image.src = 'resource.bmp?i=' + new Date().getTime();                
                }
            }
        }
    }
    xhr.open('GET', 'resource.bmp', true);
    xhr.send();
}
    </script>
  </head>
  <body>
    <img class="depends-on-resource" data-resource-name="resource.bmp" src="resource.bmp"></img>
    <button onclick="sync()">sync</button>
  </body>
</html>


0

คุณต้องใช้ชื่อไฟล์เฉพาะ แบบนี้

<img src="cars.png?1287361287" alt="">

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

<img src="cars.png?2020-02-18" alt="">

แต่คุณต้องการให้ไม่แสดงภาพจากแคช สำหรับสิ่งนี้หากเพจไม่ใช้แคชของเพจเป็นไปได้ด้วย PHP หรือฝั่งเซิร์ฟเวอร์

<img src="cars.png?<?php echo time();?>" alt="">

อย่างไรก็ตามยังไม่เป็นผล เหตุผล: แคชของเบราว์เซอร์ ... วิธีสุดท้าย แต่มีประสิทธิภาพมากที่สุดคือ Native JAVASCRIPT โค้ดง่ายๆนี้ค้นหารูปภาพทั้งหมดที่มีคลาส "NO-CACHE" และทำให้รูปภาพแทบไม่ซ้ำกัน ใส่สิ่งนี้ระหว่างแท็กสคริปต์

var items = document.querySelectorAll("img.NO-CACHE");
for (var i = items.length; i--;) {
    var img = items[i];
    img.src = img.src + '?' + Date.now();
}

การใช้งาน

<img class="NO-CACHE" src="https://upload.wikimedia.org/wikipedia/commons/6/6a/JavaScript-logo.png" alt="">

ผลลัพธ์เป็นแบบนี้

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