Creating a Connection
ทุกอย่างเริ่มต้นด้วยบรรทัดเดียว constructor คือจุดที่ WebSocket ถือกำเนิด และการตัดสินใจไม่กี่อย่างที่คุณทำตรงนี้ — เลือกใช้ scheme ไหน, subprotocol ไหน — เป็นตัวกำหนดรูปร่างของการเชื่อมต่อทั้งหมด มาแยกบรรทัดนั้นออกดูทีละส่วนกัน
ลายเซ็นของ constructor
หัวข้อที่มีชื่อว่า “ลายเซ็นของ constructor”const ws = new WebSocket(url);// or, asking for a specific application protocol:const ws = new WebSocket(url, protocols);อาร์กิวเมนต์แรก url จำเป็นต้องมี และต้องเป็น URL แบบสมบูรณ์ที่ใช้ WebSocket scheme ส่วนอาร์กิวเมนต์ที่สอง protocols เป็นทางเลือก: เป็นสตริงเดียวหรืออาร์เรย์ของสตริงที่ระบุ subprotocol ที่ client ของคุณยินดีจะพูด นั่นคือลายเซ็นทั้งหมด — URL บังคับหนึ่งตัวกับลิสต์ทางเลือกหนึ่งตัว
ws กับ wss
หัวข้อที่มีชื่อว่า “ws กับ wss”WebSocket URL ไม่เคยใช้ http แต่ใช้หนึ่งในสอง scheme เฉพาะทาง:
ws://— การเชื่อมต่อแบบไม่เข้ารหัส ไบต์เดินทางแบบเปิดเผย เหมือนhttp://ธรรมดาทุกประการwss://— โปรโตคอลเดียวกันที่ห่อด้วย TLS เหมือนhttps://ทุกประการ เข้ารหัส ยืนยันตัวตน และแก้ไขดัดแปลงได้ยากกว่ามาก
กฎในทางปฏิบัติเรียบง่าย: ใช้ wss:// สำหรับทุกอย่างที่ไม่ใช่การทดสอบในเครื่องแบบใช้แล้วทิ้ง เบราว์เซอร์ยังบังคับใช้กฎ mixed-content อีกด้วย — หน้าเว็บที่เสิร์ฟผ่าน https:// ไม่ได้รับอนุญาตให้เปิดการเชื่อมต่อ ws:// ธรรมดา ดังนั้นบนเว็บไซต์จริงทุกแห่ง wss:// จึงแทบเป็นข้อบังคับ
const dev = new WebSocket('ws://localhost:8080'); // fine for local dev onlyconst prod = new WebSocket('wss://chat.example.com'); // always this in productionSubprotocol
หัวข้อที่มีชื่อว่า “Subprotocol”argument ตัวที่สองซึ่งใส่หรือไม่ใส่ก็ได้ ช่วยให้ client กับ server ตกลงกันว่า จะพูด protocol ระดับ application ตัวไหน บน socket — เหมือนเลือกภาษากลางก่อนเริ่มบทสนทนา เบราว์เซอร์ส่งลิสต์ของคุณไป server เลือกมา หนึ่งตัว แล้วตัวที่เลือกจะกลับมาอยู่ใน ws.protocol ตอนการเชื่อมต่อเปิด
const ws = new WebSocket('wss://example.com', ['chat.v2', 'chat.v1']);ws.onopen = () => { console.log('server chose:', ws.protocol); // e.g. "chat.v2"};คุณเรียงลิสต์ตามลำดับความชอบ และ server ควรเคารพลำดับนั้น ถ้า server ไม่รองรับสักตัว ก็ควรปฏิเสธการเชื่อมต่อไปเลย subprotocol จะใส่หรือไม่ใส่ก็ได้ — หลายแอปไม่เคยใช้เลย — แต่เป็นวิธีที่สะอาดในการกำหนดเวอร์ชันของรูปแบบข้อมูลบนสาย
เกิดอะไรขึ้นในวินาทีที่คุณสร้าง socket
หัวข้อที่มีชื่อว่า “เกิดอะไรขึ้นในวินาทีที่คุณสร้าง socket”การเรียก new WebSocket(url) ไม่ บล็อก แต่คืนค่าทันทีโดย object อยู่ในสถานะ CONNECTING ระหว่างที่ handshake ทำงานอยู่เบื้องหลัง ไดอะแกรมนี้ตามรอยช่วงเวลาแรก ๆ เหล่านั้น:
sequenceDiagram participant App as Your code participant WS as WebSocket object participant Srv as Server App->>WS: new WebSocket(url, protocols) Note over WS: readyState = CONNECTING (returns immediately) WS->>Srv: HTTP Upgrade request (+ chosen protocols) Srv-->>WS: 101 Switching Protocols (picks one protocol) Note over WS: readyState = OPEN WS-->>App: onopen fires App->>WS: now safe to ws.send(...)
เพราะการสร้างคืนค่าทันที ออบเจกต์จึงยังไม่พร้อมส่งอะไรเลย — readyState ยังเป็น CONNECTING อยู่ คุณต้องผูก handler ทันทีหลังจากสร้าง แล้วรอ onopen การพยายาม send() ก่อนหน้านั้นจะ throw เราจะอาศัยหลักการนี้ในบทเรียนถัดไป
การเชื่อมต่อที่ทำงานจริง
หัวข้อที่มีชื่อว่า “การเชื่อมต่อที่ทำงานจริง”เดโมใช้ echo socket ในหน้าเว็บที่มี WebSocket API จริง จึงรันได้ทุกที่โดยไม่ต้องมี server ตัวเดโมเลียนแบบ constructor แบบสอง argument และรายงาน protocol ที่เจรจาได้ ในแอปจริงคุณจะเขียน new WebSocket('wss://your-server', ['chat.v2']) และไม่มีอะไรอื่นเปลี่ยน
ล็อกแรกพิสูจน์ว่าการสร้างคืนค่ามาโดย readyState ยังเป็น 0 อยู่ ต่อมาภายใน onopen เท่านั้นการเชื่อมต่อจึงใช้งานได้ — และ subprotocol ที่เจรจาได้ก็พร้อมใช้ตรงนั้นในรูปของ ws.protocol
| ข้อดี (Browser WebSocket API) | ข้อแลกเปลี่ยน |
|---|---|
| built-in browser API — ไม่ต้อง install library | API เรียบง่าย แต่ไม่มี reconnect built-in |
| ทำงานบน HTTP/HTTPS port เดิม (80/443) | ไม่มี message queue — ส่งขณะ connecting fail |
ws:// และ wss:// — TLS ใน URL | ไม่มี timeout built-in — ต้อง implement เอง |
| event-based — ไม่ block main thread | send() ขณะ readyState ไม่ใช่ OPEN throw error |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”ส่ง Message ก่อน Connection OPEN อาการ:
ws.send(data)ทันทีหลังnew WebSocket(url)— ยังไม่ OPENInvalidStateErrorthrow — message หาย- ส่งใน
ws.onopenเสมอ หรือ queue message แล้วส่งเมื่อ open
ไม่ Handle Connection Error อาการ:
- ไม่มี
ws.onerrorhandler - connection fail โดยไม่รู้สาเหตุ — UX แย่
- implement
onerrorและoncloseที่ log error และ trigger reconnect
💡 ตัวอย่างจากของจริง
Discord Web App:
new WebSocket('wss://gateway.discord.gg/?v=10')ตอน app load- หาก connect fail → retry ด้วย exponential backoff
Binance Web Trading:
- connect ไปยัง
wss://stream.binance.com:9443/stream- reconnect อัตโนมัติเมื่อ connection drop — trader ไม่ miss price update