跳到主要內容
版本:4.x

客戶端 API

IO

io 方法繫結至獨立建置中的全域範圍

<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
</script>

自版本 4.3.0 起,ESM 套件也已推出

<script type="module">
import { io } from "https://cdn.socket.io/4.7.5/socket.io.esm.min.js";

const socket = io();
</script>

使用 匯入地圖

<script type="importmap">
{
"imports": {
"socket.io-client": "https://cdn.socket.io/4.7.5/socket.io.esm.min.js"
}
}
</script>

<script type="module">
import { io } from "socket.io-client";

const socket = io();
</script>

否則,在所有其他情況下(使用某些建置工具,在 Node.js 或 React Native 中),可以從 socket.io-client 套件匯入

// ES modules
import { io } from "socket.io-client";

// CommonJS
const { io } = require("socket.io-client");

io.protocol

通訊協定版本號碼(目前:5)。

通訊協定定義了客戶端與伺服器之間交換封包的格式。客戶端和伺服器都必須使用相同的版本才能彼此理解。

您可以在 這裡 找到更多資訊。

io([url][, options])

為指定的 URL 建立新的 Manager,並嘗試重複使用現有的 Manager 以供後續呼叫,除非 multiplex 選項傳遞為 false。傳遞此選項等同於傳遞 "force new connection": trueforceNew: true

會傳回新的 Socket 實例,其命名空間由 URL 中的路徑名稱指定,預設為 /。例如,如果 urlhttp://localhost/users,將會建立傳輸連線至 http://localhost,並建立 Socket.IO 連線至 /users

也可以提供查詢參數,透過 query 選項或直接在 url 中提供(範例:http://localhost/users?token=abc)。

要了解底層運作方式,以下範例

import { io } from "socket.io-client";

const socket = io("ws://example.com/my-namespace", {
reconnectionDelayMax: 10000,
auth: {
token: "123"
},
query: {
"my-key": "my-value"
}
});

是此範例的簡短版本

import { Manager } from "socket.io-client";

const manager = new Manager("ws://example.com", {
reconnectionDelayMax: 10000,
query: {
"my-key": "my-value"
}
});

const socket = manager.socket("/my-namespace", {
auth: {
token: "123"
}
});

可在此處找到可用選項的完整清單 here

Manager

Manager in the class diagram for the clientManager in the class diagram for the client

Manager 管理 Engine.IO client 實例,這是建立與伺服器連線的低階引擎(使用 WebSocket 或 HTTP 長輪詢等傳輸方式)。

Manager 處理重新連線邏輯。

單一 Manager 可供多個 Sockets 使用。您可以在 這裡 找到有關此多工處理功能的更多資訊。

請注意,在多數情況下,您不會直接使用 Manager,而是使用 Socket 實例。

建構函式

new Manager(url[, options])

可在此處找到可用選項的完整清單 here

import { Manager } from "socket.io-client";

const manager = new Manager("https://example.com");

const socket = manager.socket("/"); // main namespace
const adminSocket = manager.socket("/admin"); // admin namespace

事件

事件:'error'

在連線錯誤時觸發。

socket.io.on("error", (error) => {
// ...
});

事件:'ping'

從伺服器收到 ping 封包時觸發。

socket.io.on("ping", () => {
// ...
});

事件:'reconnect'

  • attempt <數字> 重新連線嘗試次數

在成功重新連線時觸發。

socket.io.on("reconnect", (attempt) => {
// ...
});

事件:'reconnect_attempt'

  • attempt <數字> 重新連線嘗試次數

在嘗試重新連線時觸發。

socket.io.on("reconnect_attempt", (attempt) => {
// ...
});

事件:'reconnect_error'

在重新連線嘗試錯誤時觸發。

socket.io.on("reconnect_error", (error) => {
// ...
});

事件:'reconnect_failed'

在無法於 reconnectionAttempts 內重新連線時觸發。

socket.io.on("reconnect_failed", () => {
// ...
});

方法

manager.connect([callback])

manager.open([callback]) 的同義詞。

manager.open([callback])

如果管理員以 autoConnect 初始化為 false,則啟動新的連線嘗試。

callback 參數是選用的,且會在嘗試失敗/成功時呼叫。

import { Manager } from "socket.io-client";

const manager = new Manager("https://example.com", {
autoConnect: false
});

const socket = manager.socket("/");

manager.open((err) => {
if (err) {
// an error has occurred
} else {
// the connection was successfully established
}
});

manager.reconnection([value])

設定 reconnection 選項,或是在沒有傳遞任何參數的情況下回傳選項。

manager.reconnectionAttempts([value])

設定 reconnectionAttempts 選項,或是在沒有傳遞任何參數的情況下回傳選項。

manager.reconnectionDelay([value])

設定 reconnectionDelay 選項,或是在沒有傳遞任何參數的情況下回傳選項。

manager.reconnectionDelayMax([value])

設定 reconnectionDelayMax 選項,或是在沒有傳遞任何參數的情況下回傳選項。

manager.socket(nsp, options)

為指定的命名空間建立新的 Socket。僅會從 options 物件中讀取 auth ({ auth: {key: "value"} })。其他金鑰將會被忽略,且應該在實例化 new Manager(nsp, options) 時傳遞。

manager.timeout([value])

設定 timeout 選項,或是在沒有傳遞任何參數的情況下回傳選項。

Socket

Socket in the class diagram for the clientSocket in the class diagram for the client

Socket 是用於與伺服器互動的基本類別。Socket 屬於某個 命名空間 (預設為 /),並使用底層的 Manager 來進行通訊。

Socket 基本上是一個 EventEmitter,它會透過網路將事件傳送至伺服器,並從伺服器接收事件。

socket.emit("hello", { a: "b", c: [] });

socket.on("hey", (...args) => {
// ...
});

更多資訊請參閱此處

事件

事件:'connect'

此事件由 Socket 實例在連線重新連線時觸發。

socket.on("connect", () => {
// ...
});
警告

不應在 connect 處理常式中註冊事件處理常式,因為每次 Socket 實例重新連線時都會註冊新的處理常式

錯誤 ⚠️

socket.on("connect", () => {
socket.on("data", () => { /* ... */ });
});

正確 👍

socket.on("connect", () => {
// ...
});

socket.on("data", () => { /* ... */ });

事件:'connect_error'

此事件在連線失敗時觸發。

原因自動重新連線?
無法建立低階連線(暫時性失敗)✅ 是
伺服器在 中間件函式 中拒絕連線❌ 否

socket.active 屬性表示 Socket 是否會在 隨機延遲 後自動嘗試重新連線

socket.on("connect_error", (error) => {
if (socket.active) {
// temporary failure, the socket will automatically try to reconnect
} else {
// the connection was denied by the server
// in that case, `socket.connect()` must be manually called in order to reconnect
console.log(error.message);
}
});

事件:'disconnect'

  • reason <string>
  • details <DisconnectDetails>

此事件在中斷連線時觸發。

socket.on("disconnect", (reason, details) => {
// ...
});

以下是可能原因的清單

原因說明自動重新連線?
io 伺服器中斷連線伺服器已使用 socket.disconnect() 強制中斷 Socket 連線❌ 否
io 客戶端中斷連線已使用 socket.disconnect() 手動中斷 Socket 連線❌ 否
ping 超時伺服器未在 pingInterval + pingTimeout 範圍內傳送 PING✅ 是
傳輸中斷連線已中斷(例如:使用者已失去連線,或網路已從 WiFi 變更為 4G)✅ 是
傳輸錯誤連線遇到錯誤(範例:伺服器在 HTTP 長輪詢週期中被中斷)✅ 是

socket.active 屬性表示 Socket 是否會在 隨機延遲 後自動嘗試重新連線

socket.on("disconnect", (reason) => {
if (socket.active) {
// temporary disconnection, the socket will automatically try to reconnect
} else {
// the connection was forcefully closed by the server or the client itself
// in that case, `socket.connect()` must be manually called in order to reconnect
console.log(reason);
}
});

屬性

socket.active

socket 是否會自動嘗試重新連線。

此屬性可在連線失敗後使用

socket.on("connect_error", (error) => {
if (socket.active) {
// temporary failure, the socket will automatically try to reconnect
} else {
// the connection was denied by the server
// in that case, `socket.connect()` must be manually called in order to reconnect
console.log(error.message);
}
});

或在中斷連線後使用

socket.on("disconnect", (reason) => {
if (socket.active) {
// temporary disconnection, the socket will automatically try to reconnect
} else {
// the connection was forcefully closed by the server or the client itself
// in that case, `socket.connect()` must be manually called in order to reconnect
console.log(reason);
}
});

socket.connected

socket 目前是否已連線至伺服器。

const socket = io();

console.log(socket.connected); // false

socket.on("connect", () => {
console.log(socket.connected); // true
});

socket.disconnected

socket 目前是否已中斷與伺服器的連線。

const socket = io();

console.log(socket.disconnected); // true

socket.on("connect", () => {
console.log(socket.disconnected); // false
});

socket.id

socket 會話的唯一識別碼。在觸發 connect 事件後設定,並在 reconnect 事件後更新。

const socket = io();

console.log(socket.id); // undefined

socket.on("connect", () => {
console.log(socket.id); // "G5p5..."
});
警告

id 屬性是一個臨時識別碼,不應在應用程式中使用(或僅用於除錯目的),因為

  • 此識別碼會在每次重新連線後重新產生(例如當 WebSocket 連線中斷,或當使用者重新整理頁面時)
  • 兩個不同的瀏覽器分頁會有兩個不同的識別碼
  • 伺服器上沒有為特定識別碼儲存訊息佇列(亦即,如果客戶端中斷連線,伺服器傳送至此識別碼的訊息會遺失)

請改用一般會話識別碼(透過 cookie 傳送,或儲存在 localStorage 中並在 auth 酬載中傳送)。

另請參閱

socket.io

對應的 Manager 參考。

socket.on("connect", () => {
const engine = socket.io.engine;
console.log(engine.transport.name); // in most cases, prints "polling"

engine.once("upgrade", () => {
// called when the transport is upgraded (i.e. from HTTP long-polling to WebSocket)
console.log(engine.transport.name); // in most cases, prints "websocket"
});

engine.on("packet", ({ type, data }) => {
// called for each packet received
});

engine.on("packetCreate", ({ type, data }) => {
// called for each packet sent
});

engine.on("drain", () => {
// called when the write buffer is drained
});

engine.on("close", (reason) => {
// called when the underlying connection is closed
});
});

socket.recovered

在 v4.6.0 中新增

在上次重新連線期間,連線狀態是否已成功復原。

socket.on("connect", () => {
if (socket.recovered) {
// any event missed during the disconnection period will be received now
} else {
// new or unrecoverable session
}
});

有關此功能的更多資訊,請按此

方法

socket.close()

新增於 v1.0.0

同義詞為 socket.disconnect()

socket.compress(value)

設定後續事件發射的修改器,如果值為 true,事件資料將僅會壓縮。未呼叫此方法時,預設為 true

socket.compress(false).emit("an event", { some: "data" });

socket.connect()

新增於 v1.0.0

  • 傳回 Socket

手動連接 socket。

const socket = io({
autoConnect: false
});

// ...
socket.connect();

也可以用於手動重新連接

socket.on("disconnect", () => {
socket.connect();
});

socket.disconnect()

新增於 v1.0.0

手動中斷 socket 連線。在此情況下,socket 將不會嘗試重新連接。

關聯的中斷原因

  • 用戶端:"io client disconnect"
  • 伺服器端:"client namespace disconnect"

如果這是 Manager 的最後一個 active Socket 實例,低階連線將會關閉。

socket.emit(eventName[, ...args][, ack])

發射事件至由字串名稱識別的 socket。可以包含任何其他參數。所有可序列化資料結構都受支援,包括 Buffer

socket.emit("hello", "world");
socket.emit("with-binary", 1, "2", { 3: "4", 5: Buffer.from([6, 7, 8]) });

ack 參數是選用的,將會在伺服器回答時呼叫。

用戶端

socket.emit("hello", "world", (response) => {
console.log(response); // "got it"
});

伺服器

io.on("connection", (socket) => {
socket.on("hello", (arg, callback) => {
console.log(arg); // "world"
callback("got it");
});
});

socket.emitWithAck(eventName[, ...args])

在 v4.6.0 中新增

發射事件並預期從伺服器取得確認的 Promise 版本

// without timeout
const response = await socket.emitWithAck("hello", "world");

// with a specific timeout
try {
const response = await socket.timeout(10000).emitWithAck("hello", "world");
} catch (err) {
// the server did not acknowledge the event in the given delay
}

以上的範例等同於

// without timeout
socket.emit("hello", "world", (val) => {
// ...
});

// with a specific timeout
socket.timeout(10000).emit("hello", "world", (err, val) => {
// ...
});

在接收端

io.on("connection", (socket) => {
socket.on("hello", (arg1, callback) => {
callback("got it"); // only one argument is expected
});
});
警告

不支援 Promises 的環境將需要加入 polyfill 才能使用此功能。

socket.listeners(eventName)

繼承自 EventEmitter 類別

傳回名為 eventName 的事件的監聽器陣列。

socket.on("my-event", () => {
// ...
});

console.log(socket.listeners("my-event")); // prints [ [Function] ]

socket.listenersAny()

新增於 v3.0.0

傳回已註冊的萬用監聽器清單。

const listeners = socket.listenersAny();

socket.listenersAnyOutgoing()

新增於 v4.5.0

傳回已註冊的萬用監聽器清單,用於傳送封包。

const listeners = socket.listenersAnyOutgoing();

socket.off([eventName][, listener])

繼承自 EventEmitter 類別

從名為 eventName 的事件的監聽器陣列中移除指定的 listener

const myListener = () => {
// ...
}

socket.on("my-event", myListener);

// then later
socket.off("my-event", myListener);

listener 參數也可以省略

// remove all listeners for that event
socket.off("my-event");

// remove all listeners for all events
socket.off();

socket.offAny([listener])

新增於 v3.0.0

移除先前註冊的監聽器。如果未提供監聽器,則會移除所有萬用監聽器。

const myListener = () => { /* ... */ };

socket.onAny(myListener);

// then, later
socket.offAny(myListener);

socket.offAny();

socket.offAnyOutgoing([listener])

新增於 v4.5.0

移除先前註冊的監聽器。如果未提供監聽器,則會移除所有萬用監聽器。

const myListener = () => { /* ... */ };

socket.onAnyOutgoing(myListener);

// remove a single listener
socket.offAnyOutgoing(myListener);

// remove all listeners
socket.offAnyOutgoing();

socket.on(eventName, callback)

繼承自 EventEmitter 類別

為指定的事件註冊新的處理常式。

socket.on("news", (data) => {
console.log(data);
});

// with multiple arguments
socket.on("news", (arg1, arg2, arg3, arg4) => {
// ...
});
// with callback
socket.on("news", (cb) => {
cb(0);
});

socket.onAny(callback)

新增於 v3.0.0

註冊新的萬用監聽器。

socket.onAny((event, ...args) => {
console.log(`got ${event}`);
});
警告

確認不會被萬用監聽器捕捉到。

socket.emit("foo", (value) => {
// ...
});

socket.onAnyOutgoing(() => {
// triggered when the event is sent
});

socket.onAny(() => {
// not triggered when the acknowledgement is received
});

socket.onAnyOutgoing(callback)

新增於 v4.5.0

註冊新的萬用監聽器,用於傳送封包。

socket.onAnyOutgoing((event, ...args) => {
console.log(`got ${event}`);
});
警告

確認不會被萬用監聽器捕捉到。

socket.on("foo", (value, callback) => {
callback("OK");
});

socket.onAny(() => {
// triggered when the event is received
});

socket.onAnyOutgoing(() => {
// not triggered when the acknowledgement is sent
});

socket.once(eventName, callback)

繼承自 EventEmitter 類別

為名為 eventName 的事件新增一次性的 listener 函式。下次觸發 eventName 時,此監聽器會被移除,然後呼叫。

socket.once("my-event", () => {
// ...
});

socket.open()

新增於 v1.0.0

socket.connect() 的同義詞。

socket.prependAny(callback)

新增於 v3.0.0

註冊新的萬用監聽器。監聽器會新增至監聽器陣列的開頭。

socket.prependAny((event, ...args) => {
console.log(`got ${event}`);
});

socket.prependAnyOutgoing(callback)

新增於 v4.5.0

註冊新的萬用監聽器,用於監聽傳送封包。監聽器會新增至監聽器陣列的開頭。

socket.prependAnyOutgoing((event, ...args) => {
console.log(`got ${event}`);
});

socket.send([...args][, ack])

傳送 message 事件。請參閱 socket.emit(eventName[, ...args][, ack])

socket.timeout(value)

v4.4.0 中新增

設定後續事件發射的修改器,當經過指定毫秒數且未收到伺服器確認時,會以錯誤呼叫回呼。

socket.timeout(5000).emit("my-event", (err) => {
if (err) {
// the server did not acknowledge the event in the given delay
}
});

旗標

旗標:'volatile'

新增於 v3.0.0

設定後續事件發射的修改器,表示如果發生下列情況,封包可能會被捨棄:

  • socket 未連線
  • 底層傳輸無法寫入(例如,當 HTTP 長輪詢模式中已有正在執行的 POST 要求)
socket.volatile.emit(/* ... */); // the server may or may not receive it