การตั้งค่าสตรีมวิดีโอด้วย Spring Framework และ Chrome

Aug 19 2020

เรากำลังเขียนบริการ Spring ที่ทำให้ปลายทาง HTTP พร้อมใช้งานซึ่งสามารถสตรีมไฟล์วิดีโอ (หรือเสียง) จากร้านค้า Amazon S3 ได้ แนวคิดพื้นฐานคือคุณสามารถพิมพ์ url ในแถบที่อยู่ของ Google Chrome จากนั้นบริการจะดึงไฟล์จาก S3 และสตรีมในลักษณะที่ผู้ใช้สามารถเริ่มรับชมได้ทันทีโดยไม่ต้องรอให้ดาวน์โหลด เสร็จสมบูรณ์และผู้ใช้สามารถคลิกที่จุดสุ่มในแถบความคืบหน้าของวิดีโอและเริ่มดูวิดีโอจากจุดนั้นได้ทันที

วิธีที่ฉันเข้าใจว่าควรใช้ในทางทฤษฎีคือ Chrome เริ่มดาวน์โหลดไฟล์ บริการตอบสนองด้วย HTTP 200 และรวมถึงAccept-Ranges: bytesและContent-Length: filesizeส่วนหัว filesizeเป็นที่รู้จักกันเพราะเราสามารถสอบถามว่าข้อมูลเมตาจาก S3 โดยไม่ต้องเรียกไฟล์ทั้งหมด การรวมส่วนหัวเหล่านี้จะทำให้เบราว์เซอร์ยกเลิกการดาวน์โหลดและขอไฟล์อีกครั้งพร้อมกับRange: bytes=0-whateverส่วนหัว (โดยwhateverที่ Chrome ตัดสินใจว่าจะมีขนาดชิ้นส่วนขนาดไหน) จากนั้นบริการจะตอบสนองด้วย HTTP 206 (เนื้อหาบางส่วน) และช่วงไบต์ที่ร้องขอซึ่งเราสามารถระบุได้ง่ายเนื่องจาก S3 รองรับโปรโตคอลช่วงเดียวกัน จากนั้น Chrome จะขอชิ้นส่วนต่อเนื่องจากบริการจนกว่าสตรีมจะสิ้นสุด

ในฝั่ง Spring เรากำลังส่งข้อมูลออกไปในรูปแบบResponseEntity<InputStreamResource>(ตามคำตอบ SO นี้ )

อย่างไรก็ตามในทางปฏิบัติเราสังเกตว่าแม้ว่า Chrome จะยกเลิกคำขอแรกหลังจากไม่กี่ร้อยไบต์ อย่างไรก็ตามจะส่งคำขอที่สองพร้อมRange: bytes=0-ส่วนหัวเพื่อขอไฟล์ทั้งหมดอย่างมีประสิทธิภาพ เซิร์ฟเวอร์ตอบสนองด้วย HTTP 206 ด้วยเหตุนี้จึงมีการดาวน์โหลดวิดีโอเพียงไม่กี่ร้อยไบต์และเห็นได้ชัดว่าวิดีโอไม่เริ่มเล่น

น่าสนใจใน Firefox ทุกอย่างทำงานได้อย่างถูกต้อง ขออภัยแอปของเราต้องรองรับ Chrome เราขาดบางส่วนของโปรโตคอลหรือไม่?

คำตอบ

2 jqno Sep 01 2020 at 21:28

ปรากฎว่าเรามีข้อผิดพลาดแบบ off-by-one ในContent-Rangeส่วนหัวการตอบกลับ

Content-Range: bytes start-end/totalไวยากรณ์ ด้วยtotalของ10ถ้าคุณต้องการที่จะได้รับทั้งช่วงคุณจะต้องระบุbytes 0-9/10ไม่ได้0-10/10ซึ่งเป็นสิ่งที่เราทำ

แน่นอนว่าด้วยขนาดไฟล์จริงที่ใหญ่กว่าและช่วงที่แท้จริงของไฟล์ดังกล่าวข้อผิดพลาดนี้สังเกตได้ยากกว่าตัวอย่างที่สร้างไว้ในย่อหน้าก่อนหน้านี้มาก ... ಠ_ಠ