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

เผยแพร่: 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