แคชสไตล์ วิธีลบการแคชไฟล์ css และ js การรีเฟรชหน้าบางครั้งช่วยประหยัด
การรวม CSS และ Javascript ภายนอก ทำให้เราต้องการให้มีคำขอ HTTP ที่ไม่จำเป็นเหลือน้อยที่สุด
สำหรับสิ่งนี้ ไฟล์ .js และ .css จะมีส่วนหัวที่ให้การแคชที่เชื่อถือได้
แต่ถ้าไฟล์เหล่านี้มีการเปลี่ยนแปลงระหว่างการพัฒนาล่ะ ผู้ใช้ทุกคนมีเวอร์ชันเก่าในแคช - จนกว่าแคชจะล้าสมัย การร้องเรียนจำนวนมากจะเกิดขึ้นเกี่ยวกับการรวมเซิร์ฟเวอร์และชิ้นส่วนไคลเอ็นต์ที่เสียหาย
วิธีที่ถูกต้องในการแคชและการกำหนดเวอร์ชันช่วยขจัดปัญหานี้ได้อย่างสมบูรณ์ และทำให้แน่ใจได้ว่าการซิงโครไนซ์เวอร์ชันสไตล์ / สคริปต์ที่เชื่อถือได้และโปร่งใส
แคช ETag อย่างง่าย
วิธีที่ง่ายที่สุดในการแคชทรัพยากรแบบคงที่คือการใช้ ETag
เพียงพอที่จะเปิดใช้งานการตั้งค่าเซิร์ฟเวอร์ที่เหมาะสม (สำหรับ Apache จะเปิดใช้งานโดยค่าเริ่มต้น) - และ ETag จะมอบให้กับแต่ละไฟล์ในส่วนหัว - แฮชที่ขึ้นอยู่กับเวลาอัปเดต ขนาดไฟล์และ (บนระบบไฟล์ที่ใช้ไอโหนด ) ไอโหนด
เบราว์เซอร์จะแคชไฟล์ดังกล่าว และระบุส่วนหัว If-None-Match จาก ETag ของเอกสารที่แคชไว้ เมื่อได้รับส่วนหัวดังกล่าว เซิร์ฟเวอร์สามารถตอบกลับด้วยรหัส 304 จากนั้นเอกสารจะถูกนำออกจากแคช
ดูเหมือนว่านี้:
คำขอแรกไปยังเซิร์ฟเวอร์ (ล้างแคช) GET /misc/pack.js HTTP / 1.1 โฮสต์: site
โดยทั่วไป เบราว์เซอร์มักจะเพิ่มส่วนหัว เช่น User-Agent, Accept เป็นต้น พวกเขาถูกตัดให้สั้นลง
การตอบสนองของเซิร์ฟเวอร์ เซิร์ฟเวอร์ส่งในการตอบกลับเอกสารที่มีรหัส 200 และ ETag: HTTP / 1.x 200 ตกลง การเข้ารหัสเนื้อหา: gzip ประเภทเนื้อหา: ข้อความ / javascript; ชุดอักขระ = utf-8 Etag: "3272221997" ช่วงที่ยอมรับ: ไบต์ ความยาวเนื้อหา: 23321 วันที่: วันศุกร์ 02 พฤษภาคม 2551 17:22:46 น. GMT เซิร์ฟเวอร์: lighttpd คำขอเบราว์เซอร์ถัดไป คำขอเบราว์เซอร์ถัดไปในคำขอถัดไป เบราว์เซอร์เพิ่มถ้าไม่มีการจับคู่: (แคช ETag): GET /misc/pack.js HTTP / 1.1 โฮสต์: ไซต์ If-None-Match: "45370005" การตอบสนองของเซิร์ฟเวอร์ เซิร์ฟเวอร์กำลังค้นหา - ใช่ เอกสารไม่มีการเปลี่ยนแปลง ซึ่งหมายความว่าคุณสามารถออกรหัส 304 และไม่ส่งเอกสารอีก HTTP / 1.x 304 ไม่ได้แก้ไขการเข้ารหัสเนื้อหา: gzip Etag: "45370005" ประเภทเนื้อหา: ข้อความ / javascript; charset = utf-8 ยอมรับช่วง: ไบต์ วันที่: อังคาร 15 เมษายน 2008 10:17:11 GMT
อีกทางหนึ่ง หากเอกสารมีการเปลี่ยนแปลง เซิร์ฟเวอร์จะส่ง 200 พร้อม ETag ใหม่
บันเดิล Last-Modified + If-Modified-Since ทำงานในลักษณะเดียวกัน:
- เซิร์ฟเวอร์ส่งวันที่แก้ไขล่าสุดในส่วนหัว Last-Modified (แทน ETag)
- เบราว์เซอร์แคชเอกสาร และในคำขอถัดไปสำหรับเอกสารเดียวกัน จะส่งวันที่ของเวอร์ชันแคชในส่วนหัว If-Modified-Since (แทนที่จะเป็น If-None-Match)
- เซิร์ฟเวอร์ตรวจสอบวันที่ และถ้าเอกสารไม่เปลี่ยนแปลง จะส่งเฉพาะรหัส 304 ไม่มีเนื้อหา
วิธีการเหล่านี้ทำงานได้อย่างเสถียรและดี แต่เบราว์เซอร์ต้องดำเนินการตามต้องการสำหรับแต่ละสคริปต์หรือสไตล์
แคชอัจฉริยะ การกำหนดเวอร์ชัน
แนวทางทั่วไปสำหรับการกำหนดเวอร์ชันนั้นสรุปโดยย่อ:
- เพิ่มเวอร์ชัน (หรือวันที่แก้ไข) ให้กับสคริปต์ทั้งหมด ตัวอย่างเช่น http: // เว็บไซต์ / my.jsจะกลายเป็น http: //site / my.v1.2.js
- สคริปต์ทั้งหมดถูกฮาร์ดแคชโดยเบราว์เซอร์
- เมื่อสคริปต์ถูกอัปเดต เวอร์ชันจะเปลี่ยนเป็นเวอร์ชันใหม่: http: // site / my.v2.0.js
- ที่อยู่มีการเปลี่ยนแปลงดังนั้นเบราว์เซอร์จะขอและแคชไฟล์อีกครั้ง
- เวอร์ชันเก่า 1.2 จะค่อยๆ หลุดออกจากแคช
ฮาร์ดแคช
ฮาร์ดแคช- ค้อนขนาดใหญ่ชนิดหนึ่งที่ตอกย้ำคำขอไปยังเซิร์ฟเวอร์สำหรับเอกสารที่แคชไว้อย่างสมบูรณ์
ในการดำเนินการนี้ เพียงเพิ่มส่วนหัว Expires และ Cache-Control: max-age
ตัวอย่างเช่น ในการแคชเป็นเวลา 365 วันใน PHP:
ส่วนหัว ("หมดอายุ:" .gmdate ("D, d M Y H: i: s", เวลา () + 86400 * 365) "GMT"); ส่วนหัว ("การควบคุมแคช: max-age =" + 86400 * 365);
หรือคุณสามารถแคชเนื้อหาเป็นเวลานานโดยใช้ mod_header ใน Apache:
เมื่อได้รับส่วนหัวดังกล่าว เบราว์เซอร์จะฮาร์ดแคชเอกสารเป็นเวลานาน การเรียกเอกสารเพิ่มเติมทั้งหมดจะให้บริการโดยตรงจากแคชของเบราว์เซอร์ โดยไม่ต้องติดต่อกับเซิร์ฟเวอร์
เบราว์เซอร์ส่วนใหญ่ (Opera, Internet Explorer 6+, Safari) ไม่แคชเอกสารหากมีเครื่องหมายคำถามอยู่ในที่อยู่ เนื่องจากจะถือว่าเป็นไดนามิก
นี่คือเหตุผลที่เราเพิ่มเวอร์ชันลงในชื่อไฟล์ แน่นอน ด้วยที่อยู่ดังกล่าว คุณต้องใช้โซลูชันเช่น mod_rewrite เราจะพิจารณาเรื่องนี้ในบทความต่อไป
ป.ล. แต่ Firefox แคชที่อยู่ด้วยเครื่องหมายคำถาม ..
แปลชื่ออัตโนมัติ
เรามาดูวิธีการเปลี่ยนเวอร์ชันอัตโนมัติและโปร่งใสโดยไม่ต้องเปลี่ยนชื่อไฟล์กัน
ชื่อรุ่น -> ไฟล์
สิ่งที่ง่ายที่สุดคือการเปลี่ยนชื่อเวอร์ชันเป็นชื่อไฟล์ดั้งเดิม
ที่ระดับ Apache สามารถทำได้ด้วย mod_rewrite:
RewriteEngine บน RewriteRule ^ / (. * \.) V + \. (Css | js | gif | png | jpg) $ / $ 1 $ 2 [L]
กฎนี้ประมวลผลไฟล์ css / js / gif / png / jpg ทั้งหมด โดยแยกเวอร์ชันออกจากชื่อ
ตัวอย่างเช่น:
/images/logo.v2.gif -> /images/logo.gif
/css/style.v1.27.css -> /css/style.css
/javascript/script.v6.js -> /javascript/script.js
แต่นอกเหนือจากการตัดเวอร์ชัน คุณต้องเพิ่มส่วนหัวที่ฮาร์ดแคชลงในไฟล์ด้วย สำหรับสิ่งนี้จะใช้คำสั่ง mod_header:
เพิ่มส่วนหัว "หมดอายุ" "จันทร์ 28 ก.ค. 2014 23:30:00 GMT" เพิ่มส่วนหัว "การควบคุมแคช" "อายุสูงสุด = 315360000"
และเมื่อรวมกันแล้วจะใช้การกำหนดค่า apache ดังกล่าว:
RewriteEngine บน # จะลบเวอร์ชันและในขณะเดียวกันก็ตั้งค่าตัวแปรที่ไฟล์เป็นเวอร์ชัน RewriteRule ^ / (. * \.) V + \. (Css | js | gif | png | jpg) $ / $ 1 $ 2 # ไฟล์เวอร์ชันฮาร์ดแคช ส่วนหัวเพิ่ม "หมดอายุ" "จันทร์ 28 ก.ค. 2014 23:30:00 GMT" env = VERSIONED_FILE ส่วนหัวเพิ่ม "Cache-Control" "max-age = 315360000" env = VERSIONED_FILE
เนื่องจากวิธีการทำงานของโมดูล mod_rewrite ต้องวาง RewriteRule ไว้ในไฟล์การกำหนดค่าหลัก httpd.conf หรือในไฟล์ที่เชื่อมต่ออยู่ แต่ไม่ว่าในกรณีใดใน .htaccess มิฉะนั้น คำสั่ง Header จะถูกเรียกใช้ก่อน ติดตั้งตัวแปร VERSIONED_FILE
คำสั่งส่วนหัวสามารถอยู่ที่ใดก็ได้ แม้แต่ใน .htaccess ก็ไม่ต่างกัน
เพิ่มเวอร์ชันให้กับชื่อไฟล์ในหน้า HTML โดยอัตโนมัติ
วิธีใส่เวอร์ชันในชื่อสคริปต์ขึ้นอยู่กับระบบเทมเพลตของคุณและโดยทั่วไปแล้ว วิธีเพิ่มสคริปต์ (สไตล์ ฯลฯ)
ตัวอย่างเช่น เมื่อใช้วันที่แก้ไขเป็นเวอร์ชันและเครื่องมือเทมเพลต Smarty ลิงก์สามารถตั้งค่าได้ดังนี้:
ฟังก์ชันเวอร์ชันเพิ่มเวอร์ชัน:
ฟังก์ชั่น smarty_version ($ args) ($ stat = stat ($ GLOBALS ["config"] ["site_root"]. $ Args ["src"]); $ version = $ stat ["mtime"]; echo preg_replace ("! \. (+?) $! "," .v $ version. \ $ 1 ", $ args [" src "]);)
ผลลัพธ์ในหน้า:
การเพิ่มประสิทธิภาพ
เพื่อหลีกเลี่ยงการเรียกสถิติที่ไม่จำเป็น คุณสามารถจัดเก็บอาร์เรย์ที่แสดงรายการเวอร์ชันปัจจุบันในตัวแปรแยกต่างหาก
$ รุ่น ["css"] = อาร์เรย์ ("group.css" => "1.1", "other.css" => "3.0")
ในกรณีนี้ HTML จะถูกแทนที่ด้วยเวอร์ชันปัจจุบันจากอาร์เรย์
คุณสามารถข้ามทั้งสองวิธีและออกเวอร์ชันตามวันที่แก้ไขในระหว่างการพัฒนา - เพื่อความเกี่ยวข้องและในการผลิต - เวอร์ชันจากอาร์เรย์สำหรับประสิทธิภาพ
การบังคับใช้
วิธีการแคชนี้ทำงานได้ทุกที่ รวมถึง Javascript, CSS, รูปภาพ, ภาพยนตร์แฟลช ฯลฯ
เอกสารจะมีประโยชน์เมื่อมีการเปลี่ยนแปลง แต่เบราว์เซอร์ควรมีเวอร์ชันปัจจุบันอยู่เสมอ
การแคชที่กำหนดค่าอย่างเหมาะสมจะมอบประสิทธิภาพที่เพิ่มขึ้นอย่างมาก ช่วยประหยัดแบนด์วิดท์ และลดค่าใช้จ่ายของเซิร์ฟเวอร์ แต่ไซต์จำนวนมากไม่ได้นำการแคชไปใช้อย่างเหมาะสม ทำให้เกิดสภาวะการแย่งชิงที่นำไปสู่การไม่ซิงค์ระหว่างทรัพยากรที่เกี่ยวข้อง
แนวทางปฏิบัติที่ดีที่สุดสำหรับการแคชส่วนใหญ่จัดอยู่ในรูปแบบใดรูปแบบหนึ่งจากสองรูปแบบ:
รูปแบบ # 1: เนื้อหาที่ไม่เปลี่ยนรูปและอายุสูงสุดของแคช
การควบคุมแคช: อายุสูงสุด = 31536000- เนื้อหาใน URL จะไม่เปลี่ยนแปลง ดังนั้น ...
- เบราว์เซอร์หรือ CDN สามารถแคชทรัพยากรเป็นเวลาหนึ่งปีโดยไม่มีปัญหา
- เนื้อหาแคชที่มีอายุน้อยกว่าอายุสูงสุดที่ระบุสามารถใช้ได้โดยไม่ต้องปรึกษาเซิร์ฟเวอร์
หน้าหนังสือ : ฉันต้องการ "/script-v1.js", "/styles-v1.css" และ "/cats-v1.jpg" 10:24
แคช : ฉันว่าง แล้วเซิร์ฟเวอร์ของคุณล่ะ? 10:24
เซิร์ฟเวอร์ : ตกลง พวกเขาอยู่ที่นั่น อย่างไรก็ตาม เงินสดควรใช้ให้หมดภายในหนึ่งปี ไม่มาก 10:25
แคช : ขอบคุณ! 10:25
หน้าหนังสือ : ไชโย! 10:25
วันถัดไป
หน้าหนังสือ : เฮ้ฉันต้องการ "/ script- v2.js "," / รูปแบบ- v2.css "และ" /cats-v1.jpg "08:14
แคช : มีรูปแมวด้วย ที่เหลือไม่มี เซิร์ฟเวอร์? 08:14
เซิร์ฟเวอร์ : ง่าย - นี่คือ CSS & JS ใหม่ อีกครั้งที่ Cash: อายุการเก็บรักษาไม่เกินหนึ่งปี 08:15
แคช : สุด! 08:15
หน้าหนังสือ : ขอบคุณ! 08:15
แคช : อืม ฉันไม่ได้ใช้ "/script-v1.js" & "/styles-v1.css" มานานพอแล้ว ถึงเวลาที่จะลบพวกเขา 12:32
เมื่อใช้รูปแบบนี้ คุณจะไม่มีวันเปลี่ยนเนื้อหาของ URL ใดโดยเฉพาะ คุณเปลี่ยน URL เอง:
ทุก URL มีบางอย่างที่เปลี่ยนแปลงไปพร้อมกับเนื้อหา ซึ่งอาจเป็นหมายเลขเวอร์ชัน วันที่แก้ไข หรือแฮชของเนื้อหา (นี่คือตัวเลือกที่ฉันเลือกสำหรับบล็อกของฉัน)
เฟรมเวิร์กฝั่งเซิร์ฟเวอร์ส่วนใหญ่มีเครื่องมือในการทำสิ่งนี้ได้อย่างง่ายดาย (ใน Django ฉันใช้ Manifest Static Files Storage); นอกจากนี้ยังมีไลบรารีขนาดเล็กมากใน Node.js ที่ทำสิ่งเดียวกัน เช่น gulp-rev
อย่างไรก็ตาม รูปแบบนี้ไม่เหมาะกับสิ่งต่างๆ เช่น บทความและโพสต์ในบล็อก ไม่สามารถกำหนดเวอร์ชัน URL ของพวกเขาและเนื้อหาสามารถเปลี่ยนแปลงได้ อย่างจริงจัง ฉันมีข้อผิดพลาดด้านไวยากรณ์และเครื่องหมายวรรคตอนจำนวนมาก และจำเป็นต้องสามารถอัปเดตเนื้อหาได้อย่างรวดเร็ว
รูปแบบ # 2: เนื้อหาที่เปลี่ยนแปลงได้ซึ่งตรวจสอบใหม่เสมอบนเซิร์ฟเวอร์
การควบคุมแคช: ไม่มีแคช- เนื้อหาของ URL จะเปลี่ยนไป ดังนั้น ...
- เวอร์ชันแคชในเครื่องไม่สามารถใช้งานได้โดยไม่ต้องระบุเซิร์ฟเวอร์
หน้าหนังสือ : สวัสดี ฉันต้องการเนื้อหาของ "/ about /" และ "/sw.js" 11:32
แคช : ช่วยไม่ได้ เซิร์ฟเวอร์? 11:32
เซิร์ฟเวอร์ : มีดังกล่าว เงินสด เก็บไว้กับตัว แต่ถามก่อนใช้ 11:33
แคช : ครับผม! 11:33
หน้าหนังสือ : ขอบคุณ! 11:33
วันถัดไป
หน้าหนังสือ : เฮ้ ฉันต้องการเนื้อหาของ "/ about /" และ "/sw.js" อีกครั้ง 09:46
แคช : รอสักครู่. เซิร์ฟเวอร์ สำเนาของฉันโอเคไหม สำเนาของ "/ about /" มาจากวันจันทร์ และ "/sw.js" มาจากเมื่อวาน 09:46
เซิร์ฟเวอร์ : "/sw.js" ไม่เปลี่ยนแปลง ... 09:47
แคช : เย็น. หน้า กด "/sw.js" ค้างไว้ 09:47
เซิร์ฟเวอร์ : ... แต่ "/ เกี่ยวกับ /" ฉันมีเวอร์ชันใหม่แล้ว เงินสด อุ้มเธอ แต่เหมือนครั้งที่แล้ว อย่าลืมถามฉันก่อน 09:47
แคช : เข้าใจแล้ว! 09:47
หน้าหนังสือ : ดี! 09:47
หมายเหตุ: ไม่มีแคชไม่ได้หมายความว่า "ไม่แคช" แต่หมายถึง "ตรวจสอบ" (หรือตรวจสอบอีกครั้ง) ทรัพยากรที่แคชจากเซิร์ฟเวอร์ ไม่มีร้านค้าสั่งไม่ให้เบราว์เซอร์แคชเลย นอกจากนี้ ต้องตรวจสอบอีกครั้งไม่ได้หมายถึงการตรวจสอบความถูกต้องอีกครั้ง แต่ความจริงที่ว่าทรัพยากรที่แคชถูกใช้ก็ต่อเมื่ออายุน้อยกว่าอายุสูงสุดที่ระบุ มิฉะนั้นจะมีการตรวจสอบอีกครั้งเท่านั้น นั่นเป็นวิธีที่เริ่มต้นด้วยการแคชคำหลัก
ในรูปแบบนี้ คุณสามารถเพิ่ม ETag (ID เวอร์ชันที่คุณเลือก) หรือส่วนหัว Last-Modified ในการตอบกลับ ในการขอเนื้อหาจากไคลเอนต์ครั้งต่อไป มันจะแสดงผล If-None-Match หรือ If-Modified-Since ตามลำดับ ทำให้เซิร์ฟเวอร์สามารถพูดว่า “ใช้สิ่งที่คุณมี แคชของคุณเป็นปัจจุบัน” ซึ่งก็คือการส่งคืน HTTP 304.
หากไม่สามารถส่ง ETag / Last-Modified เซิร์ฟเวอร์จะส่งเนื้อหาทั้งหมดเสมอ
รูปแบบนี้ต้องมีการร้องขอเครือข่ายเสมอ ดังนั้นจึงไม่ดีเท่ากับรูปแบบแรกที่สามารถทำได้โดยไม่ต้องร้องขอเครือข่าย
ไม่ใช่เรื่องแปลกเมื่อเราไม่มีโครงสร้างพื้นฐานสำหรับรูปแบบแรกแต่ปัญหากับคำขอเครือข่ายในรูปแบบที่ 2 อาจเกิดขึ้นได้เช่นกัน ด้วยเหตุนี้ จึงใช้ตัวเลือกระดับกลาง: อายุสูงสุดสั้นและเนื้อหาที่ไม่แน่นอน นี่เป็นการประนีประนอมที่ไม่ดี
การใช้อายุสูงสุดกับเนื้อหาที่เปลี่ยนแปลงได้มักเป็นทางเลือกที่ผิด
และน่าเสียดายที่มันแพร่หลาย หน้า Github สามารถนำมาเป็นตัวอย่างได้
จินตนาการ:
- / บทความ /
- /styles.css
- /script.js
ด้วยส่วนหัวฝั่งเซิร์ฟเวอร์:
การควบคุมแคช: ต้องตรวจสอบใหม่ อายุสูงสุด = 600
- การเปลี่ยนแปลงเนื้อหา URL
- หากเบราว์เซอร์มีแคชเวอร์ชันใหม่ 10 นาที จะใช้โดยไม่ปรึกษาเซิร์ฟเวอร์
- หากไม่มีแคชดังกล่าว คำขอเครือข่ายจะถูกใช้ อาจใช้ If-Modified-Since หรือ If-None-Match
หน้าหนังสือ : ฉันต้องการ "/ article /", "/script.js" และ "/styles.css" 10:21
แคช : ฉันไม่มีอะไรเหมือนคุณ เซิร์ฟเวอร์? 10:21
เซิร์ฟเวอร์ : ไม่มีปัญหา พวกเขาอยู่ที่นี่ แต่จำไว้ว่าเงินสด: สามารถใช้ได้ภายใน 10 นาทีข้างหน้า 10:22
แคช : มี! 10:22
หน้าหนังสือ : ขอบคุณ! 10:22
หน้าหนังสือ : สวัสดี ฉันต้องการ "/ article /", "/script.js" และ "/styles.css" อีกครั้ง 10:28
แคช : อ๊ะ ขออภัย ฉันทำ "/styles.css" หาย แต่ฉันมีอย่างอื่นอีก เอาไปเถอะ เซิร์ฟเวอร์ คุณปรับแต่ง "/styles.css" ให้ฉันได้ไหม 10:28
เซิร์ฟเวอร์ : ง่าย ๆ มันเปลี่ยนไปแล้วตั้งแต่ครั้งสุดท้ายที่คุณหยิบมันขึ้นมา คุณสามารถใช้ได้อย่างปลอดภัยในอีก 10 นาทีข้างหน้า 10:29
แคช : ไม่มีปัญหา. 10:29
หน้าหนังสือ : ขอบคุณ! แต่ดูเหมือนว่ามีบางอย่างผิดพลาด! ทุกอย่างพังทลาย! เกิดอะไรขึ้น? 10:29
รูปแบบนี้มีสิทธิ์ที่จะมีชีวิตอยู่ในการทดสอบ แต่จะทำลายทุกอย่างในโครงการจริงและติดตามยากมาก ในตัวอย่างข้างต้น เซิร์ฟเวอร์ได้อัปเดต HTML, CSS และ JS แล้ว แต่หน้านั้นแสดงด้วย HTML และ JS แบบเก่าจากแคช ซึ่งได้เพิ่ม CSS ที่อัปเดตจากเซิร์ฟเวอร์แล้ว เวอร์ชั่นไม่ตรงกันทำให้เสียทุกอย่าง
บ่อยครั้งเมื่อทำการเปลี่ยนแปลงที่สำคัญใน HTML เราเปลี่ยนทั้ง CSS เพื่อสะท้อนโครงสร้างใหม่อย่างถูกต้อง และ JavaScript เพื่อให้ทันกับเนื้อหาและสไตล์ ทรัพยากรเหล่านี้เป็นอิสระทั้งหมด แต่ส่วนหัวของแคชไม่สามารถแสดงสิ่งนี้ได้ ด้วยเหตุนี้ ผู้ใช้อาจมีทรัพยากรหนึ่ง / สองเวอร์ชันล่าสุดและส่วนที่เหลือเป็นเวอร์ชันเก่า
max-age ถูกกำหนดให้สัมพันธ์กับเวลาตอบสนอง ดังนั้นหากทรัพยากรทั้งหมดถูกโอนเป็นส่วนหนึ่งของที่อยู่เดียวกัน ทรัพยากรเหล่านั้นจะหมดอายุพร้อมกัน แต่ก็ยังมีโอกาสเล็กน้อยที่จะยกเลิกการซิงค์ หากคุณมีเพจที่ไม่มี JavaScript หรือมีรูปแบบอื่นๆ วันที่หมดอายุของแคชจะไม่ซิงค์กัน และที่แย่กว่านั้น เบราว์เซอร์ดึงเนื้อหาจากแคชอย่างต่อเนื่อง โดยไม่ทราบว่า HTML, CSS และ JS นั้นต้องพึ่งพาซึ่งกันและกัน ดังนั้นจึงสามารถดึงเนื้อหาออกจากรายการและลืมเรื่องอื่นๆ ไปได้เลย เมื่อพิจารณาปัจจัยเหล่านี้ทั้งหมดแล้ว คุณควรเข้าใจว่าโอกาสที่เวอร์ชันที่ไม่ตรงกันนั้นค่อนข้างสูง
สำหรับผู้ใช้ ผลลัพธ์อาจเป็นรูปแบบหน้าที่ใช้งานไม่ได้หรือปัญหาอื่นๆ ตั้งแต่ข้อบกพร่องเล็กๆ น้อยๆ ไปจนถึงเนื้อหาที่ใช้ไม่ได้โดยสิ้นเชิง
โชคดีที่ผู้ใช้มีทางออกฉุกเฉิน ...
การรีเฟรชหน้าบางครั้งช่วยประหยัด
หากหน้าเว็บโหลดโดยการรีเฟรช เบราว์เซอร์จะทำการตรวจสอบซ้ำที่ฝั่งเซิร์ฟเวอร์เสมอ โดยไม่สนใจอายุสูงสุด ดังนั้น หากผู้ใช้มีปัญหาเนื่องจากอายุสูงสุด การรีเฟรชหน้าอย่างง่ายสามารถแก้ไขทุกอย่างได้ แต่แน่นอนว่าหลังจากพบช้อนแล้ว ตะกอนจะยังคงหลงเหลืออยู่และทัศนคติที่มีต่อไซต์ของคุณจะค่อนข้างแตกต่างออกไปบ้าง
พนักงานบริการสามารถยืดอายุของจุดบกพร่องเหล่านี้ได้
ตัวอย่างเช่น คุณมีพนักงานบริการในลักษณะนี้:
รุ่น Const = "2"; self.addEventListener ("ติดตั้ง", เหตุการณ์ => (event.waitUntil (caches.open (`สแตติก - $ (เวอร์ชัน)`) .then (แคช => cache.addAll (["/styles.css", "/ สคริปต์ .js "])));)); self.addEventListener ("เปิดใช้งาน", เหตุการณ์ => (//… ลบแคชเก่า…)); self.addEventListener ("ดึงข้อมูล", เหตุการณ์ => (event.respondWith (caches.match (event.request) .then (response => response || fetch (event.request)));));
พนักงานบริการนี้:
- สคริปต์แคชและสไตล์
- ใช้แคชในการแข่งขัน ไม่เช่นนั้นจะเข้าถึงเครือข่าย
หากเราเปลี่ยน CSS / JS เราจะเพิ่มหมายเลขเวอร์ชันด้วย ซึ่งทำให้เกิดการอัปเดต อย่างไรก็ตาม เนื่องจาก addAll เข้าถึงแคชก่อน เราจึงอาจลงเอยด้วยสภาวะการแข่งขันอันเนื่องมาจากเวอร์ชัน CSS & JS ที่มีอายุสูงสุดและไม่ตรงกัน
หลังจากที่แคชแล้ว เราจะมี CSS & JS ที่เข้ากันไม่ได้จนกว่าจะมีการอัปเดตพนักงานบริการในครั้งต่อไป และนี่คือกรณีที่เราไม่เข้าสู่สภาวะการแข่งขันระหว่างการอัปเดตอีกครั้ง
คุณสามารถข้ามการแคชในพนักงานบริการได้:
Self.addEventListener ("ติดตั้ง", เหตุการณ์ => (event.waitUntil (caches.open (`สแตติก - $ (เวอร์ชัน)`) .then (แคช => cache.addAll ([คำขอใหม่ ("/ styles.css", (แคช: "ไม่มีแคช")), คำขอใหม่ ("/ script.js", (แคช: "ไม่มีแคช")])));));
ขออภัย ตัวเลือกสำหรับการแคชไม่ได้รับการสนับสนุนใน Chrome / Opera และเพิ่งถูกเพิ่มใน Firefox nightly build แต่คุณสามารถทำเองได้:
Self.addEventListener ("ติดตั้ง", เหตุการณ์ => (event.waitUntil (caches.open (`สแตติก - $ (เวอร์ชัน)`) .then (แคช => Promise.all (["/styles.css", "/ script .js "] .map (url => (// cache-bust โดยใช้การดึงสตริงการสืบค้นแบบสุ่มกลับ (` $ (url)? $ (Math.random ()) `) .then (การตอบสนอง => (// ล้มเหลว บน 404, 500 ฯลฯ ถ้า (! response.ok) โยนข้อผิดพลาด ("ไม่เป็นไร"); ส่งคืน cache.put (url, ตอบกลับ);)))))));));
ในตัวอย่างนี้ ฉันกำลังล้างแคชโดยใช้ตัวเลขสุ่ม แต่คุณสามารถเพิ่มแฮชของเนื้อหาในบิลด์ได้ (ซึ่งคล้ายกับที่ sw-precache ทำ) นี่เป็นการนำ JavaScript ไปใช้ในรูปแบบแรก แต่ใช้งานได้กับพนักงานบริการเท่านั้น ไม่ใช่เบราว์เซอร์และ CDN
Service Workers และ HTTP Cache ทำงานร่วมกันได้ดี อย่าให้พวกเขาทะเลาะกัน!
อย่างที่คุณเห็น คุณสามารถแก้ไขข้อผิดพลาดในการแคชในพนักงานบริการได้ แต่ควรแก้ไขปัญหาที่ต้นทาง การตั้งค่าแคชอย่างถูกต้องไม่เพียงแต่ทำให้งานของพนักงานบริการง่ายขึ้น แต่ยังช่วยเบราว์เซอร์ที่ไม่สนับสนุนพนักงานบริการ (Safari, IE / Edge) และยังช่วยให้คุณได้รับประโยชน์สูงสุดจาก CDN ของคุณอีกด้วย
ส่วนหัวการแคชที่ถูกต้องยังช่วยให้อัปเดตพนักงานบริการได้ง่ายขึ้นอีกด้วย
รุ่น Const = "23"; self.addEventListener ("ติดตั้ง", เหตุการณ์ => (event.waitUntil (caches.open (`สแตติก - $ (เวอร์ชัน)`) .then (แคช => cache.addAll (["/", "/ script-f93bca2c. js "," /styles-a837cb1e.css "," /cats-0e9a2ef4.jpg "])));));
ที่นี่ฉันได้แคชหน้ารูทด้วยรูปแบบ # 2 (การตรวจสอบความถูกต้องทางฝั่งเซิร์ฟเวอร์) และทรัพยากรอื่น ๆ ทั้งหมดที่มีรูปแบบ # 1 (เนื้อหาที่ไม่เปลี่ยนรูป) การอัปเดตของพนักงานบริการแต่ละครั้งจะทำให้เกิดคำขอไปยังหน้าราก และทรัพยากรอื่นๆ ทั้งหมดจะถูกโหลดก็ต่อเมื่อ URL ของพวกเขามีการเปลี่ยนแปลง ข่าวดีก็คือมันช่วยประหยัดทราฟฟิกและปรับปรุงประสิทธิภาพ ไม่ว่าคุณจะอัปเกรดจากเวอร์ชันก่อนหน้าหรือเวอร์ชันที่เก่ามาก
มีข้อได้เปรียบที่สำคัญกว่าการใช้งานแบบเนทีฟที่นี่ โดยที่ไบนารีทั้งหมดจะถูกดาวน์โหลดแม้ว่าจะมีการเปลี่ยนแปลงเล็กน้อย หรือเรียกใช้การเปรียบเทียบไบนารีที่ซับซ้อน วิธีนี้ทำให้เราสามารถอัปเดตเว็บแอปพลิเคชันขนาดใหญ่ที่มีโหลดค่อนข้างน้อย
พนักงานบริการทำงานได้ดีกว่าเป็นการเพิ่มประสิทธิภาพมากกว่าการใช้ไม้ค้ำยันชั่วคราว ดังนั้นให้ทำงานกับแคชแทนการต่อสู้
เมื่อใช้อย่างระมัดระวัง เนื้อหาที่มีอายุสูงสุดและเปลี่ยนแปลงได้จะดีมาก
max-age มักเป็นตัวเลือกที่ไม่ถูกต้องสำหรับเนื้อหาที่เปลี่ยนแปลงได้ แต่ก็ไม่เสมอไป ตัวอย่างเช่น บทความต้นฉบับมีอายุสูงสุดสามนาที เงื่อนไขการแข่งขันไม่ใช่ปัญหา เนื่องจากไม่มีการขึ้นต่อกันบนหน้าที่ใช้รูปแบบแคชเดียวกัน (CSS, JS & รูปภาพใช้รูปแบบ # 1 - เนื้อหาที่ไม่เปลี่ยนรูป) อย่างอื่นไม่ได้ใช้รูปแบบนี้
รูปแบบนี้หมายความว่าฉันกำลังเขียนบทความยอดนิยมอย่างใจเย็น และ CDN (Cloudflare) ของฉันสามารถลดภาระจากเซิร์ฟเวอร์ได้ ถ้าแน่นอน ฉันยินดีที่จะรอสามนาทีเพื่อให้บทความที่อัปเดตพร้อมใช้งานสำหรับผู้ใช้
ควรใช้รูปแบบนี้โดยไม่มีความคลั่งไคล้ ถ้าฉันเพิ่มส่วนใหม่ลงในบทความ และเชื่อมโยงกับส่วนนั้นจากบทความอื่น ฉันได้สร้างการขึ้นต่อกันที่ต้องแก้ไข ผู้ใช้สามารถคลิกที่ลิงค์และรับสำเนาของบทความโดยไม่ต้องมีส่วนที่เขากำลังมองหา หากฉันต้องการหลีกเลี่ยงสิ่งนี้ ฉันต้องอัปเดตบทความ ลบเวอร์ชันแคชของบทความออกจาก Cloudflare รอสามนาที แล้วจึงเพิ่มลิงก์ไปยังบทความอื่น ใช่ รูปแบบนี้ต้องใช้ความระมัดระวัง
เมื่อใช้อย่างถูกต้อง การแคชจะช่วยเพิ่มประสิทธิภาพและประหยัดแบนด์วิดท์ได้อย่างมาก ส่งผ่านเนื้อหาที่ไม่เปลี่ยนรูปหากคุณสามารถเปลี่ยน URL ได้อย่างง่ายดาย หรือใช้การตรวจสอบความถูกต้องทางฝั่งเซิร์ฟเวอร์อีกครั้ง ผสมผสานเนื้อหาที่มีอายุสูงสุดและเนื้อหาที่เปลี่ยนแปลงได้หากคุณกล้าพอที่จะแน่ใจว่าเนื้อหาของคุณไม่มีการขึ้นต่อกันที่อาจเกิดจากการซิงค์
หลายคนคิดว่าโดยค่าเริ่มต้นไฟล์ CSS ที่เชื่อมต่อผ่านลิงก์หรือ @import จะไม่ถูกแคช ฉันต้องทำให้คุณผิดหวัง มันคือ css ที่แม่นยำซึ่งถูกแคชไว้ในไฟล์แยกต่างหาก และมันดีมาก ฉันจะบอกว่ายอดเยี่ยมมาก ข้อมูลนี้ได้รับการยืนยันอย่างน่าเชื่อถือในทั้ง 6 ตัวขึ้นไปและเบราว์เซอร์อื่นๆ เป็นที่น่าสังเกตว่าผู้เป็นที่รักจำนวนมากแคชไฟล์ดังกล่าวด้วยความเร็วที่บ้าคลั่งดังนั้นจึงเป็นที่หนึ่งสำหรับกรณีนี้ อย่างไรก็ตาม มันเป็นกลไกนี้เองที่ Opera มีความเร็วที่สำคัญในหลายกรณีเมื่อเปรียบเทียบกับเบราว์เซอร์อื่นๆ แต่ฉันจะทำการจองทันทีว่าการแคช "สุดยอด" ใน Opera นี้เป็นเรื่องตลกที่โหดร้ายเมื่อใช้เทคโนโลยี AJAX ในขณะที่คนอื่น ๆ ปรับแต่งพวงเจี๊ยบเมื่อใช้ AJAX แต่ Opera ก็ใช้อันเก่า แต่นี่เป็นเพลงของหัวข้อแยกต่างหาก
การแคช CSS
แต่! ยังมีปัญหาด้านความเศร้าโศกอยู่บ้างในทิศทางนี้ ตามกฎแล้วเกิดจากเซิร์ฟเวอร์ Apache ที่กำหนดค่าไม่ถูกต้องซึ่งสร้างส่วนหัวที่ไม่ถูกต้อง และด้วยความช่วยเหลือของส่วนหัว คุณสามารถควบคุมการแคชของไฟล์ได้ ตามค่าเริ่มต้น แคชจะเปิดใช้งานอยู่เสมอ แต่มีบางครั้งที่คุณไม่จำเป็นต้องแคชไฟล์ ด้วยเหตุนี้ ผู้เชี่ยวชาญจึงเริ่มเต้นรำกับแทมบูรีนเกี่ยวกับส่วนหัว HTTP แต่ถ้าคุณกำลังอ่านบทความนี้ทั้งหมด แสดงว่าคุณยังห่างไกลจากการจัดการส่วนหัว HTTP ฉันรับรองกับคุณว่าในอนาคตอันใกล้คุณจะไม่ต้องเผชิญกับงานดังกล่าว และหากคุณอยากรู้ถึงแก่นแท้ ฉันจะบอกคุณสั้น ๆ ว่าสิ่งนี้เกิดขึ้นได้อย่างไร
- ส่งส่วนหัว HTTP ไปยังเว็บเซิร์ฟเวอร์ - พวกเขาพูดว่า เฮ้ พริกหวาน ส่งไฟล์ CSS ให้ฉัน มิฉะนั้น ฉันมี CSS แต่ครั้งสุดท้ายที่มีการเปลี่ยนแปลงดังกล่าว
- และเซิร์ฟเวอร์ก็ตอบกลับมา น่ารักมาก ไม่มีการเปลี่ยนแปลงตั้งแต่นั้นมา ใช้ CSS เก่าของคุณอย่างกล้าหาญ
- หาก CSS เปลี่ยนไป แสดงว่าเบราว์เซอร์อัปเดต CSS ในแคชอย่างโง่เขลา
ทีนี้ ถ้าไม่เหนื่อย ก็แค่ขยะทางวิทยาศาสตร์เล็กๆ น้อยๆ จากการทดลองบางอย่าง
ฉันจะบอกคุณทันทีว่าข้อความด้านล่างจะเข้าใจได้ไม่ดีสำหรับผู้เริ่มต้นในเว็บ โดยพื้นฐานแล้วสิ่งนี้จะมีประโยชน์สำหรับผู้ที่ยังต้องเผชิญกับงานปิดการใช้งานและเปิดใช้งานแคช
การทดลองทั้งหมดดำเนินการตามจริงและจ่ายเงิน พูดตามตรงว่าโฮสต์ที่ดีที่ให้คุณเปลี่ยนโครงสร้างของส่วนหัว HTTP ได้โดยไม่ต้องหวาดระแวงว่าจะถูกแฮ็กโดยส่วนหัว HTTP :)
โหมดเบราว์เซอร์
ดังนั้นเบราว์เซอร์ใด ๆ ก็มี 2 โหมด:
1. โหมดเริ่มต้น, ชื่อเรื่องที่ส่งคืนคือ:
Cache-Control: no-store, no-cache, must-revalidate, post-check = 0, เช็คล่วงหน้า = 0
2. โหมดเปิดใช้งานแคช, ชื่อเรื่องที่ส่งคืนคือ:
การควบคุมแคช: ส่วนตัว อายุสูงสุด = 10800 ตรวจสอบล่วงหน้า = 10800
ต่อไป ฉันจะอธิบายพฤติกรรมของเบราว์เซอร์
FireFox 3.5 และสูงกว่า
ในครั้งแรกโหมดแคชไฟล์ JavaScript ภายนอกอย่างแน่นหนาและไม่ได้ตรวจสอบการอัปเดต เว้นแต่คุณจะบังคับให้หน้ารีเฟรช CSS ได้รับการตรวจสอบโดยคำขอส่วนหัว
If-Modified-Since: "วันที่ปัจจุบัน" GMT If-None-Match: " own hash code"
กล่าวคือ CSS จะโหลดซ้ำก็ต่อเมื่อได้รับการอัปเดตจริงเท่านั้น
ประการที่สองโหมดหยุดรีเฟรชหน้าโดยสิ้นเชิง นั่นคือ แม้ว่าเราจะเปลี่ยนแปลงเนื้อหาที่แสดงบนเพจในฐานข้อมูล เนื้อหาจะไม่แสดงสิ่งนี้ แม้ว่าจะถูกบังคับให้รีเฟรช เนื่องจากมันส่งคำขอ:
GET / HTTP / 1.1 โฮสต์: xxx.com หาก-แก้ไข-ตั้งแต่: วันที่ GMT ปัจจุบัน
และได้รับคำตอบว่า
HTTP / 1.1 304 ไม่ถูกแก้ไข
Internet Explorer 8 (IE8)
ในครั้งแรกโหมด Internet Explorer จะส่งคำขอ If-Modified-Since & If-None-Match สำหรับทั้ง JavaScript และ css นั่นคือจะโหลด JavaScript และ CSS เฉพาะเมื่อมีการอัปเดตจริงเท่านั้น เช่นเดียวกับถ้าเพจถูกบังคับให้รีเฟรช
ประการที่สองโหมด Internet Explorer ยังส่งคำขอ If-Modified-Since & If-None-Match สำหรับทั้ง JavaScript และ css แต่ในขณะเดียวกัน มันก็ไม่ได้พยายามโหลด / อัปเดตหน้าด้วยซ้ำ กล่าวคือ มันไม่ได้ส่งคำขอด้วยซ้ำ นั่นคือ js / css ของคุณจะได้รับการอัปเดต แต่เนื้อหาเทมเพลตและหน้าจะไม่ทำ แม้แต่การบังคับให้รีเฟรชหน้าก็ไม่ช่วยในการอัปเดตเนื้อหา
Opera 10 และเก่ากว่า
ในครั้งแรกโหมด Opera ในโหมดแรก การอัปเดต js & CSS จะขึ้นอยู่กับค่าของตัวเลือกตรวจสอบรูปภาพในการตั้งค่า หากตั้งค่าตัวเลือกเป็น เสมอ โอเปร่าจะส่งคำขอด้วย If-Modified-Since & If-None-Match เพื่อตรวจสอบการอัปเดต js & css หากมีการตั้งค่า เช่น 5 ชั่วโมง ค่านั้นจะถูกตรวจสอบทุกๆ 5 ชั่วโมง หรือโดยการบังคับให้รีเฟรชหน้า
ประการที่สองโหมด Opera จะไม่ตรวจสอบการอัปเดต js & CSS (ไม่ส่งคำขอ GET) และไม่ได้ส่งคำขอ GET สำหรับหน้านั้นด้วย นั่นคือ เราจะไม่เห็นการอัปเดต js & css หรือการอัปเดตเนื้อหาดังเช่นใน สิ่งอื่นๆ และในเบราว์เซอร์อื่นๆ แต่ด้วยการอัปเดตแบบบังคับ Opera จะดีกว่า ต่างจาก IE & FF ตรงที่ Opera ร้องขอเนื้อหาของหน้าอย่างชัดเจนโดยไม่มี If-Modified-Since & If-None-Match คำขออัปเดต Js & CSS สำหรับการบังคับให้อัปเดตมาพร้อมกับ If-Modified-Since & If-None-Match
ข้อสรุป
- การแคช หากคุณไม่เข้าใจว่ามันทำงานอย่างไรในเบราว์เซอร์ต่างๆ และผลที่ตามมา เป็นสิ่งที่ค่อนข้างอันตราย
- การแคชสามารถเปิดใช้งานได้ก็ต่อเมื่อเพจไม่ค่อยอัปเดต (นั่นคือ หากไซต์ไม่มีเพจที่อัปเดตตามเวลาจริง) และแม้ในกรณีนี้ จำเป็นต้องกำหนดขีดจำกัดในช่วงเวลาจำกัดการแคช (เช่น สองสามชั่วโมงหรือหนึ่งวัน)
- ในความคิดของฉัน FireFox มีพฤติกรรมที่ฉลาดกว่า IE เล็กน้อย เพราะถึงแม้จะปิดการใช้งานแคช มันก็ไม่ได้ตรวจสอบการอัปเดต JavaScript อย่างต่อเนื่อง ซึ่งดูสมเหตุสมผลเพราะ JavaScript มีการอัปเดตน้อยมาก
- Opera ช่วยให้คุณควบคุมการอัปเดตรูปภาพ JavaScript และ CSS ได้อย่างยืดหยุ่นโดยใช้การตั้งค่าตรวจสอบรูปภาพ ซึ่งเป็นข้อดี Opera ยังทำงานได้ดีกว่า IE & FF ด้วยการเปิดใช้งานแคชและบังคับให้รีเฟรช เนื่องจากฉันขอเตือนคุณว่า Opera จะรีเฟรชเนื้อหาของหน้าอย่างสมบูรณ์ในกรณีนี้ และ IE & FF จะทำให้คุณมีความสุข
ขอให้โชคดีและไซต์ที่ให้ผลกำไร