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

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

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

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

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

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

พิจารณา Service Worker ที่มี Listener เหตุการณ์ 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 จะดำเนินการตามคำขอจากแคชดังกล่าวได้โดยไม่ต้องใช้เครือข่ายเลย

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

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

รูปภาพหลักในโพสต์นี้เป็นผลงานของ Natalie Rhea Riggs ใน Unsplash