เผยแพร่: 6 ตุลาคม 2020
คำขอ HTTP บางรายการมีส่วนหัว Range: ซึ่งระบุว่าควรแสดงผลเฉพาะบางส่วนของทรัพยากรทั้งหมด โดยทั่วไปแล้วจะใช้สำหรับการสตรีมเนื้อหาเสียงหรือวิดีโอเพื่อให้โหลดสื่อเป็นก้อนเล็กๆ ได้ตามต้องการ แทนที่จะขอไฟล์ระยะไกลทั้งหมดในครั้งเดียว
Service Worker คือโค้ด JavaScript ที่อยู่ระหว่างเว็บแอปกับเครือข่าย ซึ่งอาจสกัดกั้นคำขอเครือข่ายขาออกและสร้างการตอบกลับสำหรับคำขอเหล่านั้น
ก่อนหน้านี้คำขอช่วงและ Service Worker ทำงานร่วมกันได้ไม่ดีนัก คุณต้องทำตามขั้นตอนพิเศษเพื่อหลีกเลี่ยงผลลัพธ์ที่ไม่ดีใน Service Worker แต่โชคดีที่ตอนนี้เริ่มมีการเปลี่ยนแปลงแล้ว ในเบราว์เซอร์ที่แสดงลักษณะการทำงานที่ถูกต้อง คำขอช่วงจะ "ทำงานได้ทันที" เมื่อส่งผ่าน Service Worker
ปัญหาคืออะไร
ลองพิจารณา Service Worker ที่มีfetchเครื่องมือฟังเหตุการณ์ต่อไปนี้ ซึ่งจะรับคำขอขาเข้าทั้งหมดและส่งต่อไปยังเครือข่าย
self.addEventListener('fetch', (event) => {
// The Range: header will not pass through in
// browsers that behave incorrectly.
event.respondWith(fetch(event.request));
});
ในเบราว์เซอร์ที่มีลักษณะการทำงานไม่ถูกต้อง หาก event.request มีส่วนหัว Range: ระบบจะทิ้งส่วนหัวนั้นโดยไม่มีการแจ้งเตือน คำขอที่เซิร์ฟเวอร์ระยะไกลได้รับจะไม่มี Range: เลย การดำเนินการนี้ไม่จำเป็นต้อง "ทำให้" สิ่งใดเสียหาย เนื่องจากในทางเทคนิคแล้ว เซิร์ฟเวอร์ได้รับอนุญาตให้แสดงเนื้อหาการตอบกลับทั้งหมดพร้อมรหัสสถานะ 200 แม้ว่าจะมีส่วนหัว Range: ในคำขอเดิมก็ตาม แต่จะส่งผลให้มีการโอนข้อมูลมากกว่าที่จำเป็นอย่างยิ่งจากมุมมองของเบราว์เซอร์
นักพัฒนาแอปที่ทราบลักษณะการทำงานนี้สามารถหลีกเลี่ยงได้โดยตรวจสอบการมีอยู่ของส่วนหัว Range: อย่างชัดเจน และไม่เรียกใช้ event.respondWith() หากมีส่วนหัวดังกล่าว การทำเช่นนี้จะทำให้ Service Worker นำตัวเองออกจากภาพการสร้างการตอบกลับได้อย่างมีประสิทธิภาพ และจะใช้ตรรกะการเชื่อมต่อเครือข่ายของเบราว์เซอร์เริ่มต้นแทน ซึ่งตรรกะนี้จะทราบวิธีรักษาคำขอช่วง
self.addEventListener('fetch', (event) => {
// Return without calling event.respondWith()
// if this is a range request.
if (event.request.headers.has('range')) {
return;
}
event.respondWith(fetch(event.request));
});
แต่ก็พูดได้ว่านักพัฒนาแอปส่วนใหญ่ไม่ทราบว่าจำเป็นต้องดำเนินการนี้ และไม่ชัดเจนว่าเหตุใดจึงต้องมีข้อกำหนดดังกล่าว ในท้ายที่สุด ข้อจำกัดนี้เกิดจากเบราว์เซอร์ที่ต้องตามให้ทันการเปลี่ยนแปลงในข้อกำหนดพื้นฐาน ซึ่งได้เพิ่มการรองรับฟังก์ชันการทำงานนี้
ปัญหาที่แก้ไขแล้ว
เบราว์เซอร์ที่ทำงานอย่างถูกต้องจะเก็บส่วนหัว Range: ไว้เมื่อส่ง event.request ไปยัง fetch() ซึ่งหมายความว่าโค้ด Service Worker ในตัวอย่างแรกจะอนุญาตให้เซิร์ฟเวอร์ระยะไกลเห็นส่วนหัว Range: หากเบราว์เซอร์ตั้งค่าไว้
self.addEventListener('fetch', (event) => {
// The Range: header will pass through in browsers
// that behave correctly.
event.respondWith(fetch(event.request));
});
ตอนนี้เซิร์ฟเวอร์มีโอกาสจัดการคำขอช่วงอย่างถูกต้องและแสดงการตอบกลับบางส่วนพร้อมรหัสสถานะ 206
เบราว์เซอร์ใดทำงานได้อย่างถูกต้อง
Safari เวอร์ชันล่าสุดมีฟังก์ชันการทำงานที่ถูกต้อง Chrome และ Edge ตั้งแต่เวอร์ชัน 87 เป็นต้นไปก็ทำงานได้อย่างถูกต้องเช่นกัน
ณ เดือนตุลาคม 2020 นี้ Firefox ยังไม่ได้แก้ไขลักษณะการทำงานนี้ คุณจึงอาจยังต้องคำนึงถึงลักษณะการทำงานนี้ขณะที่นำโค้ดของ Service Worker ไปใช้งานจริง
การตรวจสอบแถว "รวมส่วนหัวของช่วงในคำขอเครือข่าย" ของแดชบอร์ดการทดสอบแพลตฟอร์มเว็บเป็นวิธีที่ดีที่สุดในการยืนยันว่าเบราว์เซอร์ที่กำหนดได้แก้ไขลักษณะการทำงานนี้หรือไม่
แล้วคำขอช่วงการแสดงจากแคชล่ะ
Service Worker ทำได้มากกว่าแค่ส่งคำขอผ่านไปยังเครือข่าย กรณีการใช้งานทั่วไปคือการเพิ่มทรัพยากร เช่น ไฟล์เสียงและวิดีโอ ลงในแคชในเครื่อง จากนั้น Service Worker จะดำเนินการตามคำขอจากแคชนั้นได้โดยไม่ต้องผ่านเครือข่ายเลย
เบราว์เซอร์ทั้งหมด รวมถึง Firefox รองรับการตรวจสอบคำขอภายในแฮนเดิลเลอร์ fetch การตรวจสอบว่ามีส่วนหัว Range: หรือไม่ จากนั้นจึงดำเนินการตามคำขอในเครื่องด้วยการตอบกลับ 206 ที่มาจากแคช อย่างไรก็ตาม โค้ด Service Worker ที่จะแยกวิเคราะห์ส่วนหัว Range: อย่างถูกต้องและแสดงเฉพาะส่วนที่เหมาะสมของการตอบกลับที่แคชไว้ทั้งหมดนั้นไม่ใช่เรื่องง่าย
โชคดีที่นักพัฒนาแอปที่ต้องการความช่วยเหลือสามารถใช้ Workbox ซึ่งเป็นชุดไลบรารีที่ช่วยลดความซับซ้อนของกรณีการใช้งาน Service Worker ทั่วไป workbox-range-request module จะใช้ตรรกะทั้งหมดที่จำเป็นในการแสดงการตอบกลับบางส่วนจากแคชโดยตรง ดูสูตรเต็มสำหรับกรณีการใช้งานนี้ได้ในเอกสารประกอบของ Workbox