ปิดการใช้งานแคชสำหรับบางภาพ


113

ฉันสร้างภาพโดยใช้ PHP lib

บางครั้งเบราว์เซอร์ไม่โหลดไฟล์ที่สร้างขึ้นใหม่

ฉันจะปิดการใช้งานแคชเฉพาะสำหรับรูปภาพที่ฉันสร้างขึ้นแบบไดนามิกได้อย่างไร

หมายเหตุ: ฉันต้องใช้ชื่อเดียวกันสำหรับภาพที่สร้างขึ้นเมื่อเวลาผ่านไป

คำตอบ:


233

วิธีแก้ปัญหาทั่วไปและเรียบง่ายสำหรับปัญหานี้ที่ให้ความรู้สึกเหมือนแฮ็ก แต่ค่อนข้างพกพาได้คือการเพิ่มสตริงข้อความค้นหาที่สร้างแบบสุ่มให้กับคำขอสำหรับรูปภาพไดนามิกแต่ละรายการ

ตัวอย่างเช่น -

<img src="image.png" />

ก็จะกลายเป็น

<img src="image.png?dummy=8484744" />

หรือ

<img src="image.png?dummy=371662" />

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

การสร้างหมายเลขสุ่มสามารถเกิดขึ้นได้ทั้งบนเซิร์ฟเวอร์เมื่อให้บริการเพจ (ตรวจสอบให้แน่ใจว่าเพจนั้นไม่ได้ถูกแคช ... ) หรือบนไคลเอนต์ (โดยใช้ JavaScript)

คุณจะต้องตรวจสอบว่าเว็บเซิร์ฟเวอร์ของคุณสามารถรับมือกับเคล็ดลับนี้ได้หรือไม่


87
แทนที่จะใช้ตัวเลขสุ่มให้ใช้การประทับเวลาที่ข้อมูลเปลี่ยนแปลงหรือหมายเลขเวอร์ชันของข้อมูลที่สะท้อน
lhunath


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

ฉันเชื่อว่าบทความนี้อธิบายถึงสาเหตุของพฤติกรรมดังกล่าว
Metalcoder

1
สิ่งนี้ใช้ไม่ได้จริงต้องล้างภาพด้วยวิธีอื่น (โดยปกติในการครอบตัดภาพภาพจะยังคงเหมือนเดิม)
เบ็น

44

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

header ("Pragma-directive: no-cache");
header ("Cache-directive: no-cache");
header ("Cache-control: no-cache");
header ("Pragma: no-cache");
header ("Expires: 0");

1
สิ่งนี้จะใช้กับทั้งหน้า .... ฉันไม่สามารถปิดการใช้งานแคชสำหรับภาพเดียวเท่านั้น (ภาพเฉพาะจากหน้านั้น)?
dole doug

5
@Thorpe: ใช้กับการตอบสนอง HTTP สิ่งที่อยู่ในการตอบกลับไม่เกี่ยวข้อง ไม่ว่าจะเป็นข้อมูลรูปภาพข้อมูล HTML หรืออะไรก็ตาม ถ้ามันไม่ได้ผลคุณคงทำไม่ถูก ตรวจสอบส่วนหัว HTTP ในการตอบกลับของคุณเพื่อดูว่าได้รับมอบหมายอย่างถูกต้องหรือไม่
lhunath

ฉันหวังว่าจะได้ผล ... Chrome ไม่มีปัญหาใด ๆ แต่ Firefox 14 และ IE 8 ปฏิเสธที่จะรีเฟรชภาพแม้ว่าจะมีการส่งส่วนหัวด้านบนก็ตาม นี่จะเป็นวิธีแก้ปัญหาที่สะอาดกว่าการเพิ่มพารามิเตอร์ที่กำหนดเองลงในสตริงการสืบค้น ถอนหายใจ
Pawel Krakowiak

2
@PawelKrakowiak โปรดทราบว่าการเพิ่มส่วนหัวจะใช้ไม่ได้กับภาพที่แคชไว้แล้วเนื่องจากเบราว์เซอร์ไม่ได้ถามเซิร์ฟเวอร์เกี่ยวกับภาพเหล่านั้นดังนั้นจะไม่เห็นส่วนหัว พวกเขาจะทำงานสำหรับคำขอภาพใด ๆ ที่เกิดขึ้นหลังจากที่คุณเพิ่มเข้าไป
lhunath

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

13

หากคุณต้องการทำแบบไดนามิกในเบราว์เซอร์โดยใช้จาวาสคริปต์นี่คือตัวอย่าง ...

<img id=graph alt="" 
  src="http://www.kitco.com/images/live/gold.gif" 
  />

<script language="javascript" type="text/javascript">
    var d = new Date(); 
    document.getElementById("graph").src = 
      "http://www.kitco.com/images/live/gold.gif?ver=" + 
       d.getTime();
</script>

12

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

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

ใส่แท็ก ...

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

<FilesMatch "\.(jpg|jpeg)$">
FileETag MTime Size
</FilesMatch>

11

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

<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 () ได้รับเวลาแก้ไขไฟล์


4

ฉันรู้ว่าหัวข้อนี้เก่า แต่ได้รับการจัดอันดับที่ดีมากใน Google ฉันพบว่าการใส่สิ่งนี้ในส่วนหัวของคุณได้ผลดี

<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">

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

4

ฉันแค่มองหาวิธีแก้ปัญหานี้และคำตอบข้างต้นไม่ได้ผลในกรณีของฉัน (และฉันมีชื่อเสียงไม่เพียงพอที่จะแสดงความคิดเห็นเกี่ยวกับเรื่องนี้) ปรากฎว่าอย่างน้อยสำหรับกรณีการใช้งานของฉันและเบราว์เซอร์ที่ฉันใช้ (Chrome บน OSX) สิ่งเดียวที่ดูเหมือนจะป้องกันการแคชคือ:

Cache-Control = 'no-store'

เพื่อความสมบูรณ์ตอนนี้ฉันใช้ 'no-cache, no-store, must-revalidate' ทั้ง 3 ตัว

ดังนั้นในกรณีของฉัน (ให้บริการรูปภาพที่สร้างขึ้นแบบไดนามิกจาก Flask ใน Python) ฉันต้องทำสิ่งต่อไปนี้เพื่อหวังว่าจะทำงานในเบราว์เซอร์ให้ได้มากที่สุด ...

def make_uncached_response(inFile):
    response = make_response(inFile)
    response.headers['Pragma-Directive'] = 'no-cache'
    response.headers['Cache-Directive'] = 'no-cache'
    response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
    response.headers['Pragma'] = 'no-cache'
    response.headers['Expires'] = '0'
    return response

เพียงแค่วางคำตอบแบบไม่มีร้านค้าก็เพียงพอแล้วที่จะทำให้มันใช้งานได้สำหรับฉัน
scourge192

ไม่ใช่แค่บน Chrome แต่สำหรับ Firefox ตอนนี้ดูเหมือนว่าจะเป็นมาตรฐานแล้ว: developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control (ดูส่วน " การป้องกันการแคช ")
Gino Mempin

3

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

จะเป็นการดีกว่าที่จะเพิ่มการตรวจสอบเช่นข้อมูลที่รูปภาพแสดง สิ่งนี้เปิดใช้งานการแคชเมื่อเป็นไปได้


1

ลองเพิ่มอีกวิธีหนึ่งลงในพวง

การเพิ่มสตริงที่ไม่ซ้ำกันในตอนท้ายเป็นวิธีที่สมบูรณ์แบบ

example.jpg?646413154

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

เมื่ออัปเดตภาพแล้วเวลาของไฟล์จะเปลี่ยนไป

<?php
$filename = "path/to/images/example.jpg";
$filemtime = filemtime($filename);
?>

ตอนนี้ส่งออกภาพ:

<img src="images/example.jpg?<?php echo $filemtime; ?>" >

1
นั่นคือสิ่งที่ฉันใช้เนื่องจากความถูกต้องในการแคช
ยีน


0

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

ฉันได้ต่อท้ายสตริงวันที่เพื่อให้แน่ใจว่ามีการรีเฟรชอย่างน้อยทุกนาที

โค้ดตัวอย่าง (PHP):

$output .= "<img src=\"http://xy.somecounter.com/?id=1234567890&".date(ymdHi)."\" alt=\"somecounter.com\" style=\"border:none;\">";

ผลลัพธ์ในsrcลิงก์เช่น:

http://xy.somecounter.com/?id=1234567890&1207241014

0

หากคุณมี URL รูปภาพแบบฮาร์ดโค้ดตัวอย่างเช่นhttp://example.com/image.jpgคุณสามารถใช้ php เพื่อเพิ่มส่วนหัวให้กับรูปภาพของคุณ

ก่อนอื่นคุณต้องทำให้ apache ประมวลผล jpg ของคุณเป็น php ดูที่นี่: เป็นไปได้ไหมที่จะรัน PHP ด้วยนามสกุล file.php.jpg

โหลดรูปภาพ (imagecreatefromjpeg) จากไฟล์จากนั้นเพิ่มส่วนหัวจากคำตอบก่อนหน้า ใช้ส่วนหัวของฟังก์ชัน php เพื่อเพิ่มส่วนหัว

จากนั้นส่งออกภาพด้วยฟังก์ชั่น imagejpeg

โปรดสังเกตว่าการปล่อยให้ php ประมวลผลภาพ jpg นั้นไม่ปลอดภัยมาก นอกจากนี้โปรดทราบว่าฉันยังไม่ได้ทดสอบโซลูชันนี้ดังนั้นจึงขึ้นอยู่กับคุณที่จะทำให้มันใช้งานได้


-1

ง่ายส่งตำแหน่งส่วนหัวเดียว

ไซต์ของฉันมีรูปภาพหนึ่งรูปและหลังจากอัปโหลดรูปภาพไม่มีการเปลี่ยนแปลงฉันจึงเพิ่มรหัสนี้:

<?php header("Location: pagelocalimage.php"); ?>

งานสำหรับฉัน

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