การจัดการคำขอช่วงใน Service Worker

ตรวจสอบว่า Service Worker ของคุณทราบสิ่งที่ต้องทําเมื่อมีการขอการตอบกลับบางส่วน

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

Service Worker คือโค้ด JavaScript ที่อยู่ระหว่างเว็บแอปกับเครือข่าย ซึ่งอาจขัดขวางคำขอขาออกของเครือข่ายและสร้างคำตอบสำหรับคำขอเหล่านั้น

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

ปัญหาคืออะไร

ลองพิจารณา Service Worker ที่มี fetch event listener ต่อไปนี้ ซึ่งจะรับคําขอขาเข้าทุกรายการและส่งไปยังเครือข่าย

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 จะดำเนินการตามคำขอจากแคชดังกล่าวได้โดยไม่ต้องใช้เครือข่ายเลย

เบราว์เซอร์ทั้งหมด รวมถึง Firefox รองรับการตรวจสอบคําขอภายในตัวแฮนเดิล fetch ตรวจสอบว่ามีส่วนหัว Range: หรือไม่ จากนั้นตอบสนองคําขอในเครื่องด้วยการตอบกลับ 206 ที่มาจากแคช อย่างไรก็ตาม โค้ด Service Worker สำหรับการแยกวิเคราะห์ส่วนหัว Range: อย่างถูกต้องและแสดงเฉพาะส่วนที่สอดคล้องกันของการตอบกลับที่แคชไว้อย่างสมบูรณ์นั้นไม่ใช่เรื่องง่าย

แต่นักพัฒนาซอฟต์แวร์ที่ต้องการความช่วยเหลือสามารถหันมาใช้ Workbox ซึ่งเป็นชุดไลบรารีที่ลดความซับซ้อนของกรณีการใช้งาน Service Worker ทั่วไป workbox-range-request module ใช้ตรรกะทั้งหมดที่จําเป็นในการแสดงคําตอบบางส่วนจากแคชโดยตรง ดูสูตรการใช้งานทั้งหมดสำหรับกรณีการใช้งานนี้ได้ในเอกสารประกอบของ Workbox

รูปภาพหลักในโพสต์นี้โดย Natalie Rhea Riggs จาก Unsplash