WebSocket vs SSE vs WebTransport
WebSocket เป็น transport สำหรับ real-time ที่ มีความสามารถ มากที่สุด แต่ความสามารถไม่เหมือนกับความเหมาะสม รอบ ๆ WebSocket ยังมีทางเลือกอีกสามแบบ แต่ละแบบยอมแลกพลังบางส่วนทิ้งไปเพื่อความเรียบง่าย ความเข้ากันได้ หรือความเร็วล้วน ๆ การรู้ว่าแต่ละแบบชนะตรงไหนช่วยให้คุณไม่ต้องแบก full duplex socket — พร้อมกลไก reconnection, heartbeat และ auth ที่ตามมา — ทั้งที่ของเบากว่าก็พอใช้แล้ว
สี่ตัวเลือก
หัวข้อที่มีชื่อว่า “สี่ตัวเลือก”- WebSocket — การเชื่อมต่อเดียว ถาวร และ สองทาง ฝั่งใดก็ส่ง message ได้ทุกเมื่อ เรียงลำดับและเชื่อถือได้ เป็นค่าตั้งต้นเมื่อ traffic ไหลทั้งสองทางจริง ๆ: แชต การทำงานร่วมกัน multiplayer คำสั่งแบบสด
- Server-Sent Events (SSE) — HTTP response ที่อยู่ยาวซึ่ง stream event ที่เป็น text จาก server → client เท่านั้น client ส่งย้อนกลับทางเดิมไม่ได้ (ต้องใช้ HTTP request ธรรมดาแทน) แลกมาด้วยความเรียบง่ายสุด ๆ วิ่งบน HTTP ธรรมดา และ
EventSourceของเบราว์เซอร์ reconnect ให้อัตโนมัติ แล้วต่อยอดจาก event id ล่าสุด เหมาะสำหรับ feed: การแจ้งเตือน dashboard ticker ราคา progress log - Long-polling — ไม่ใช่ transport แบบ stream จริง ๆ แต่เป็น fallback client ส่ง HTTP request แล้ว server ถือ request นั้นค้างไว้จนกว่าจะมีอะไรจะพูด ตอบกลับ แล้ว client ก็ขอใหม่ทันที วิธีนี้ทำงานได้ผ่าน proxy หรือ stack เก่าแก่แทบทุกแบบ โดยแลกกับ latency และ overhead ไลบรารีมักใช้เป็นการลดระดับอย่างนุ่มนวลเมื่อ WebSocket หรือ SSE โดนบล็อก
- WebTransport — น้องใหม่ สร้างบน HTTP/3 (QUIC) ให้ทั้ง stream ที่เชื่อถือได้และเรียงลำดับ และ datagram ที่ไม่เชื่อถือได้และไม่เรียงลำดับ บนการเชื่อมต่อเดียว พร้อม multiplexing ที่หลีกเลี่ยง head-of-line blocking มุ่งเป้าไปที่ media และเกมความถี่สูงและไวต่อ latency ที่การทิ้งแพ็กเก็ตเก่าดีกว่าการรอ retransmit ยังใหม่กว่า WebSocket และยังไม่รองรับทั่วทุกที่
เลือกหนึ่งตัว
หัวข้อที่มีชื่อว่า “เลือกหนึ่งตัว”การตัดสินใจมักหลุดออกมาจากสองคำถาม: ข้อมูลไหลในทิศทางใดบ้าง และ traffic ทนต่อการสูญหายเพื่อแลกกับความเร็วได้หรือไม่?
flowchart TD q1["Does the client need to send<br/>messages mid-connection?"] q1 -- "No — server pushes only" --> q2["Need to resume a stream<br/>and reconnect for free?"] q2 -- "Yes, and plain HTTP is fine" --> sse["Server-Sent Events"] q2 -- "Legacy proxies break streaming" --> poll["Long-polling fallback"] q1 -- "Yes — both directions" --> q3["High-frequency media, or<br/>OK to drop stale packets?"] q3 -- "No — ordered, reliable messages" --> ws["WebSocket"] q3 -- "Yes — datagrams / low latency" --> wt["WebTransport (HTTP/3)"]
อ้างอิงอย่างรวดเร็ว เทียบกันแบบเคียงข้าง:
| Transport | ทิศทาง | Protocol | Auto-reconnect | การส่ง | เหมาะที่สุดสำหรับ |
| --- | --- | --- | --- | --- |
| WebSocket | สองทาง | TCP, HTTP Upgrade | คุณสร้างเอง | เรียงลำดับ เชื่อถือได้ | แชต การทำงานร่วมกัน คำสั่ง |
| SSE | server → client | HTTP (text/event-stream) | มีในตัว (EventSource) | เรียงลำดับ เชื่อถือได้ | feed การแจ้งเตือน dashboard |
| Long-polling | วน request/response | HTTP | ไม่มี (ขอใหม่) | เชื่อถือได้ latency สูงกว่า | fallback ผ่าน proxy เก่า |
| WebTransport | สองทาง | HTTP/3 (QUIC) | คุณสร้างเอง | stream หรือ datagram | เกม media แบบ real-time |
สิ่งที่มักทำให้คนสะดุด
หัวข้อที่มีชื่อว่า “สิ่งที่มักทำให้คนสะดุด”ข้อเท็จจริงไม่กี่อย่างที่เปลี่ยนการออกแบบจริง:
- SSE มีงบประมาณการเชื่อมต่อต่อ origin. บน HTTP/1.1 เบราว์เซอร์จำกัดจำนวนการเชื่อมต่อพร้อมกันต่อ host (โดยทั่วไปคือหก) และ
EventSourceที่อยู่ยาวกินไปหนึ่ง การเปิดหลายแท็บไปยัง origin เดียวกันอาจใช้โควตาจนหมด บน HTTP/2 ขีดจำกัดนี้แทบหายไปเพราะ stream ถูก multiplex - SSE เป็น text เท่านั้น. event เป็น UTF-8 text ถ้าจะส่ง binary ต้อง base64-encode ก่อน ซึ่งเปลืองไบต์เพิ่มราวหนึ่งในสาม WebSocket และ WebTransport พา binary ได้ในตัว
- WebTransport datagram ไม่เชื่อถือได้โดยตั้งใจ. datagram อาจหายหรือมาถึงแบบสลับลำดับ และไม่มีการ retransmit เลย นั่นเป็น ฟีเจอร์ สำหรับ media แบบสด — เฟรมวิดีโอจากเมื่อ 200 ms ที่แล้วไร้ประโยชน์ ข้ามไปเลยดีกว่ารอ ถ้าคุณต้องการความเชื่อถือได้ ให้ใช้ WebTransport stream แทน
- “Real-time” แทบไม่เคยแปลว่าสองทาง. ฟีเจอร์จำนวนน่าแปลกใจมีแต่การ push จาก server ไปยัง client สำหรับสิ่งเหล่านั้น SSE ขจัดความกังวลของ WebSocket ทั้งชุด — ไม่ต้อง reconnect เอง ไม่ต้อง heartbeat ปลอม ๆ เพื่อจำลองความมีชีวิต — แบบฟรี ๆ
ค่าตั้งต้นที่ใช้งานได้จริง
หัวข้อที่มีชื่อว่า “ค่าตั้งต้นที่ใช้งานได้จริง”ถ้าข้อมูลไหลจาก server ไปยัง client เท่านั้นและมี HTTP ธรรมดาให้ใช้ ให้คว้า SSE ก่อน คุณจะเขียน code น้อยลง ถ้า client ต้องส่งด้วย ให้ใช้ WebSocket — สุกงอมแล้ว รองรับทั่วทุกที่ และเป็นเส้นทางที่ส่วนที่เหลือของคอร์สนี้เตรียมคุณไว้แล้ว เก็บ long-polling ไว้ในกระเป๋าหลังเป็น fallback สำหรับเครือข่ายที่เป็นปฏิปักษ์ ส่วน WebTransport ก็จับตาไว้ระหว่างที่ยังสุกงอมขึ้นเรื่อย ๆ สำหรับงานเกมและ media ที่ datagram สำคัญ จับคู่ transport ให้เข้ากับ traffic ไม่ใช่เข้ากับกระแสฮือฮา
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”ใช้ WebSocket เมื่อ SSE เพียงพอ อาการ:
- ต้องการเฉพาะ server push (notification, live feed) แต่เลือก WebSocket
- complexity สูงกว่า SSE โดยไม่ได้ benefit
- SSE ง่ายกว่า: auto-reconnect, native EventSource API, ทำงานบน HTTP/2
เลือก WebTransport เพราะ “ใหม่กว่า” อาการ:
- WebTransport browser support ยังไม่ครบ (Safari ยังไม่รองรับ)
- production app ที่ต้องการ wide support ยังไม่เหมาะ
- ใช้ WebTransport เมื่อต้องการ UDP semantics: game ที่ latency สำคัญกว่า reliability
💡 ตัวอย่างจากของจริง
GitHub: ใช้ SSE สำหรับ live event stream — one-way push ที่ไม่ต้องการ bidirectional
Google Meet: ใช้ WebRTC (SRTP/DTLS) สำหรับ audio/video — UDP-based delivery ลด latency
Discord: ใช้ WebSocket — ต้องการ bidirectional (user action ↔ server event)