คำแนะนำวิธีบีบอัดคำขอ HTTP ของไคลเอ็นต์เว็บ

หากคุณพบว่าตัวเองอยู่ในสถานการณ์ที่คุณส่งเพย์โหลดคำขอ HTTP ขนาดใหญ่จากเว็บเบราว์เซอร์ไปยัง API ของคุณ คุณอาจทำผิดพลาดทางสถาปัตยกรรมหรือการออกแบบ กล่าวคือ เมื่อเร็วๆ นี้ทีมของเราอยู่ในสถานการณ์ที่การส่งคำขอขนาด 200–300KB เป็นประจำทำให้เราได้รับการแลกเปลี่ยนน้อยที่สุด

ด้วยเหตุนี้ เราจึงพบว่าเวลาในการโอนคำขอยาวนาน ต่างจากวิธีที่เบราว์เซอร์ขยายขนาดเนื้อหาการตอบสนอง HTTP โดยอัตโนมัติผ่านกลไก การเจรจาต่อรองเนื้อหา HTTP (โดยใช้ส่วนหัว Accept-Encoding) เบราว์เซอร์ไม่ได้บีบอัดเนื้อหาคำขอของเราโดยอัตโนมัติ แน่นอนว่ามีกลไกที่คล้ายกันที่เราสามารถทำได้สำหรับกรณีนี้

เราผิด

การค้นหาสิ่งใดก็ตามที่เกี่ยวข้องกับการบีบอัดเนื้อหาคำขอฝั่งไคลเอ็นต์นั้น "ส่วนใหญ่" ไร้ผล เท่าที่เราต้องการหลีกเลี่ยงการ "โกนจามรี" ที่ Axiom Zen สัตว์ร้ายตัวนี้ก็ต้องตัดผม

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

ก่อนที่เราจะใช้การบีบอัด GZIP ฝั่งไคลเอ็นต์เป็นโซลูชันของเรา เราได้สำรวจทางเลือกต่างๆ มากมาย:

Msgpack ดูมีแนวโน้มดี อย่างไรก็ตาม มันไม่มีประสิทธิภาพสำหรับคำขอจำนวนมากซึ่งเป็นปัญหาของเราอย่างแน่นอน นอกจากนี้ ดูเหมือนว่าจะมีความรู้สึกเชิงลบเล็กน้อยต่อ Msgpack จากนักพัฒนาบนเว็บไซต์ต่างๆ

gRPCนึกถึงตอนที่เราใช้มันเป็นโปรโตคอลการสื่อสารไมโครเซอร์วิสที่ประสบความสำเร็จ อย่างไรก็ตาม ยังไม่รองรับบนฝั่งเบราว์เซอร์ ดังนั้นเราจึงต้องดำเนินการต่อไป

ท้ายที่สุด JSONC แสดงให้เห็นศักยภาพ แต่จำเป็นต้องมีการเปลี่ยนแปลงโครงสร้างข้อมูลของเราโดยไม่สำคัญตามคำจำกัดความ และโครงการก็มีปัญหาที่เปิดอยู่มากมายเกี่ยวกับการเข้ารหัสแบบไปกลับบน GitHub เราตัดสินใจที่จะผ่าน

GZIP เป็น G6 ของเรา

เนื่องจากอัลกอริทึม GZIP มีมาระยะหนึ่งแล้ว เราจึงหวังว่าจะมีคนนำไปใช้ใน Javascript เรากล้าฝันว่ามันจะเป็น Javascript ที่สามารถทำงานในเบราว์เซอร์ได้เช่นกัน โชคดีที่การค้นหาของเราพาเราไปที่ หน้า pako npm และจากการทดสอบและเกณฑ์มาตรฐาน ดูเหมือนว่าเป็นเพียงแพ็คเกจที่เรากำลังมองหา

สำหรับการผสานรวมกับฐานโค้ดฝั่งไคลเอ็นต์ของคุณ หากคุณใช้ axios ซึ่งเป็นไลบรารีคำขอ Javascript HTTP ทั่วไป ทางออกที่ดีที่สุดของคุณน่าจะรวมเข้ากับตัวแปลงคำขอทั่วโลก:

โปรดสังเกตว่าเราส่งคำขอ GZIP ในขนาดที่กำหนดเท่านั้น การซิปข้อมูลจำนวนเล็กน้อยจะเพิ่มขนาดโดยรวม โดยที่ 1,024 ไบต์ถือเป็น "ตัวเลขมหัศจรรย์กึ่งกำหนดเอง" เราขอแนะนำให้เล่นซอเพื่อค้นหาสิ่งที่ดีที่สุดสำหรับคุณ

สำหรับฝ่ายรับ Axiom Zen มักจะเขียนโค้ดแบ็กเอนด์ใน Go (golang) สิ่งนี้กลายเป็นการแสดงที่ยอดเยี่ยมถึงพลังและความสง่างามของอินเทอร์เฟซใน Go ดังที่เห็นในตัวอย่างของเล่นนี้:

สังเกตว่าฟังก์ชัน json.NewDecoder() ไม่สนใจว่า io.Reader จะถูกส่งไปอย่างไร

อีกสิ่งหนึ่งที่ควรทราบ (ไม่ได้แสดงไว้ที่นี่) ก็คือ หากคุณต้องการแชร์ทรัพยากรข้ามแหล่งที่มา (CORS) คุณจะต้องเพิ่มส่วนหัว Content-Encoding ลงในรายการ Access-Control-Allow-Headers เมื่อจัดการก่อน คำขอ -flightOPTIONS

ผลลัพธ์

เราเห็นการลดขนาดลง 10 เท่า (ข้อมูล JSON ค่อนข้างซ้ำกันตามธรรมชาติ) โดยมีการลงโทษ CPU เล็กน้อยฝั่งไคลเอ็นต์ แม้ว่าแนวทางของเราอาจต้องมีการปรับแต่งจากฝั่งของคุณ แต่เราพอใจกับผลลัพธ์ที่ได้ ซึ่งจะเห็นได้ชัดเจนเป็นพิเศษเมื่อพูดคุยกับเซิร์ฟเวอร์ที่อยู่ห่างไกล

แจ้งให้เราทราบว่าคุณคิดอย่างไรเกี่ยวกับแนวทางของเราในความคิดเห็นด้านล่าง!

เขียนโดย Chris Scott และทีมวิศวกร Axiom Zen
เรียบเรียงโดย "Yasmine Nadery" และ "Bryce Bladon"

ดูเรื่องราวประเภทนี้เพิ่มเติมได้ใน บล็อกของ Axiom Zen