cover

傳統 HTTP 就像打電話給客服——你問一個問題、對方回答、掛斷。WebSocket 是讓你跟伺服器之間「保持通話不掛斷」的技術。

先講結論

WebSocket 提供全雙工通訊——伺服器可以主動推送資料給客戶端,不需要客戶端先發請求。適合即時聊天、股票行情、多人遊戲這類需要「一有新資料馬上送」的場景。不是所有應用都需要 WebSocket,大部分 CRUD 用 REST 就夠了。

為什麼 HTTP 不夠用?

HTTP 是「請求-回應」模式:客戶端問、伺服器答、結束。伺服器沒辦法主動找客戶端說話。

那如果要做即時通知呢?傳統有兩種做法:

  • 輪詢(Polling):每隔幾秒發一次請求問「有新消息嗎?」——99% 的請求回來都是「沒有」。浪費頻寬又浪費 CPU。就像每五分鐘問一次「到了嗎」的副駕。
  • 長輪詢(Long Polling):發請求後伺服器不馬上回應,等到有新資料才回——比輪詢好,但每次回應完又要重新建立連線。

WebSocket 一勞永逸:建立一次連線,之後雙方隨時互發訊息。

怎麼建立連線

WebSocket 從一個 HTTP 請求開始,然後「升級」成 WebSocket 協定:

客戶端:「嘿,我想升級成 WebSocket」
GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade

伺服器:「好,升級成功」
HTTP/1.1 101 Switching Protocols
Upgrade: websocket

握手完成後,連線就從 HTTP 變成 WebSocket 了。之後的通訊不再是 HTTP,而是更輕量的 WebSocket frame。

前端怎麼用

瀏覽器原生就支援 WebSocket API,不用裝任何套件:

const socket = new WebSocket('wss://example.com/socket');
 
socket.onopen = () => {
  console.log('已連線');
  socket.send('Hello Server!');
};
 
socket.onmessage = (event) => {
  console.log('收到:', event.data);
};
 
socket.onclose = () => console.log('連線已關閉');
socket.onerror = (error) => console.error('錯誤:', error);

就這樣。四個事件處理器:onopenonmessageoncloseonerror。比你想像的簡單很多。

動手做:5 分鐘即時聊天室

看概念不如直接寫一個。

Server(Node.js)

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
const clients = new Set();
 
wss.on('connection', (ws) => {
  clients.add(ws);
  ws.on('message', (message) => {
    const data = JSON.parse(message);
    // 廣播給所有人
    clients.forEach(client => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(JSON.stringify({
          user: data.user,
          text: data.text,
          time: new Date().toLocaleTimeString()
        }));
      }
    });
  });
  ws.on('close', () => clients.delete(ws));
});

Client(純 HTML)

<div id="messages" style="height:300px;overflow-y:auto;border:1px solid #ccc;padding:10px"></div>
<input id="name" placeholder="你的名字" />
<input id="input" placeholder="輸入訊息..." />
<button onclick="send()">送出</button>
<script>
  const ws = new WebSocket('ws://localhost:8080');
  ws.onmessage = (e) => {
    const data = JSON.parse(e.data);
    messages.innerHTML += `<p><b>${data.user}</b> [${data.time}]: ${data.text}</p>`;
  };
  function send() {
    const text = input.value;
    if (text) {
      ws.send(JSON.stringify({ user: name.value || '匿名', text }));
      input.value = '';
    }
  }
  input.addEventListener('keypress', (e) => { if (e.key === 'Enter') send(); });
</script>
mkdir ws-chat && cd ws-chat && npm init -y && npm i ws
# 建立 server.js,啟動 node server.js
# 開兩個瀏覽器分頁,打開 index.html,即時聊天!

這個 demo 展示了 WebSocket 的三個核心特性:全雙工(Server 主動 push)、持久連線(不用每次重新握手)、廣播(一人發訊息,所有人收到)。

WebSocket vs HTTP

HTTPWebSocket
連線短連線(請求-回應)長連線(持續保持)
方向單向(客戶端發起)雙向
延遲較高極低
適合一般 CRUD即時互動

正式產品還需要什麼

Demo 能跑,但離正式產品還差:心跳機制(ping/pong 防 timeout)、自動重連(斷線後重連)、房間機制(不是所有人都收到)、認證(連線時驗 token)。

實務上大多會用 Socket.IO——它幫你處理好自動重連、房間、fallback 到 long polling 等雜事。或者如果你只需要伺服器單向推送,Server-Sent Events(SSE) 更簡單。


不是所有東西都需要即時——但需要即時的時候,HTTP 真的救不了你。


延伸閱讀

阮一峰的网络日志 - WebSocket 教程 MDN - WebSocket API 概念 RESTFul API