伺服器 API
伺服器


相關文件頁面
建構函式
new Server(httpServer[, options])
httpServer
<http.Server>
|<https.Server>
options
<Object>
import { createServer } from "http";
import { Server } from "socket.io";
const httpServer = createServer();
const io = new Server(httpServer, {
// options
});
io.on("connection", (socket) => {
// ...
});
httpServer.listen(3000);
可用選項的完整清單可以在這裡找到。
new Server(port[, options])
import { Server } from "socket.io";
const io = new Server(3000, {
// options
});
io.on("connection", (socket) => {
// ...
});
可用選項的完整清單可以在這裡找到。
new Server(options)
options
<Object>
import { Server } from "socket.io";
const io = new Server({
// options
});
io.on("connection", (socket) => {
// ...
});
io.listen(3000);
可用選項的完整清單可以在這裡找到。
事件
事件:'connect'
同義詞為事件:'connection'。
事件:'connection'
socket
(Socket) 與客戶端建立 socket 連線
於與客戶端建立連線時觸發。
io.on("connection", (socket) => {
// ...
});
事件:'new_namespace'
namespace
Namespace
於建立新的命名空間時觸發
io.on("new_namespace", (namespace) => {
// ...
});
例如,這可能有助於
- 將共用中介軟體附加至每個命名空間
io.on("new_namespace", (namespace) => {
namespace.use(myMiddleware);
});
- 追蹤動態建立的命名空間
io.of(/\/nsp-\w+/);
io.on("new_namespace", (namespace) => {
console.log(namespace.name);
});
屬性
server.engine
參考基礎的 Engine.IO 伺服器。請參閱此處。
server.sockets
主命名空間 (/
) 的別名。
io.sockets.emit("hi", "everyone");
// is equivalent to
io.of("/").emit("hi", "everyone");
方法
server.adapter([value])
設定轉接器 value
。預設為與 socket.io 一起提供的 Adapter
實例,其為基於記憶體。請參閱 socket.io-adapter。如果未提供任何參數,此方法會傳回目前的值。
import { Server } from "socket.io";
import { createAdapter } from "@socket.io/redis-adapter";
import { createClient } from "redis";
const io = new Server();
const pubClient = createClient({ host: "localhost", port: 6379 });
const subClient = pubClient.duplicate();
io.adapter(createAdapter(pubClient, subClient));
// redis@3
io.listen(3000);
// redis@4
Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
io.listen(3000);
});
server.attach(httpServer[, options])
httpServer
<http.Server>
|<https.Server>
options
<Object>
將 Server
附加至 httpServer
,並使用提供的 options
。
import { createServer } from "http";
import { Server } from "socket.io";
const httpServer = createServer();
const io = new Server();
io.attach(httpServer);
io.on("connection", (socket) => {
// ...
});
httpServer.listen(3000);
server.attach(port[, options])
將 Server
附加至提供的 port
,並使用提供的 options
。
import { Server } from "socket.io";
const io = new Server();
io.attach(3000);
io.on("connection", (socket) => {
// ...
});
server.attachApp(app[, options])
將 Socket.IO 伺服器附加到 µWebSockets.js 應用程式
import { App } from "uWebSockets.js";
import { Server } from "socket.io";
const app = App();
const io = new Server();
io.attachApp(app);
io.on("connection", (socket) => {
// ...
});
app.listen(3000, (token) => {
if (!token) {
console.warn("port already in use");
}
});
server.bind(engine)
engine
<engine.Server>
- 傳回
<Server>
僅供進階使用。將伺服器繫結到特定的 engine.io Server
(或相容的 API) 執行個體。
import { Server } from "socket.io";
import { Server as Engine } from "engine.io";
const engine = new Engine();
const io = new Server();
io.bind(engine);
engine.listen(3000);
server.close([callback])
callback
<Function>
關閉 Socket.IO 伺服器並斷開所有用戶端連線。callback
參數為選用,且將在所有連線關閉時呼叫。
這也會關閉底層的 HTTP 伺服器。
import { createServer } from "http";
import { Server } from "socket.io";
const PORT = 3030;
const io = new Server(PORT);
io.close();
const httpServer = createServer();
httpServer.listen(PORT); // PORT is free to use
io.attach(httpServer);
僅關閉底層的 HTTP 伺服器是不夠的,因為這只會阻止伺服器接受新的連線,但透過 WebSocket 連線的用戶端不會立即斷開連線。
參考:https://node.dev.org.tw/api/http.html#serverclosecallback
server.disconnectSockets([close])
於 v4.0.0 新增
別名為 io.of("/").disconnectSockets(close)
。
// make all Socket instances disconnect
io.disconnectSockets();
// make all Socket instances in the "room1" room disconnect (and close the low-level connection)
io.in("room1").disconnectSockets(true);
這個方法也可以在多個 Socket.IO 伺服器叢集中使用,搭配相容的轉接器,例如 Postgres 轉接器。
在這種情況下,如果你只想影響給定節點上的 socket 實例,你需要使用 local
旗標
// make all Socket instances that are currently connected on the given node disconnect
io.local.disconnectSockets();
請參閱 這裡。
server.emit(eventName[, ...args])
歷史
版本 | 變更 |
---|---|
v4.5.0 | io.emit() 現在支援確認。 |
v1.0.0 | 初始實作。 |
向主命名空間中所有已連線的用戶端發送事件。
io.emit("hello");
可以包含任意數量的參數,並且支援所有可序列化的資料結構
io.emit("hello", 1, "2", { "3": 4 }, Buffer.from([5]));
在接收端
socket.on("hello", (arg1, arg2, arg3, arg4) => {
console.log(arg1); // 1
console.log(arg2); // "2"
console.log(arg3); // { "3": 4 }
console.log(arg4); // ArrayBuffer or Buffer, depending on the platform
});
參數會自動序列化,因此不需要呼叫 JSON.stringify()
。
你可以使用 to()
和 except()
將封包傳送給特定用戶端
// the “hello” event will be broadcast to all connected clients that are either
// in the "room1" room or in the "room2" room, excluding those in the "room3" room
io.to("room1").to("room2").except("room3").emit("hello");
從版本 4.5.0
開始,現在可以在廣播時使用確認
io.timeout(10000).emit("some-event", (err, responses) => {
if (err) {
// some clients did not acknowledge the event in the given delay
} else {
console.log(responses); // one response per client
}
});
在這種情況下,呼叫 timeout()
是必要的。
server.emitWithAck(eventName[, ...args])
在 v4.6.0 中新增
eventName
<string>
|<symbol>
args
any[]
- 傳回
Promise<any[]>
廣播並預期從所有目標用戶端收到確認的 Promise 版本
try {
const responses = await io.timeout(10000).emitWithAck("some-event");
console.log(responses); // one response per client
} catch (e) {
// some clients did not acknowledge the event in the given delay
}
上述範例等同於
io.timeout(10000).emit("some-event", (err, responses) => {
if (err) {
// some clients did not acknowledge the event in the given delay
} else {
console.log(responses); // one response per client
}
});
在接收端
socket.on("some-event", (callback) => {
callback("got it"); // only one argument is expected
});
server.except(rooms)
於 v4.0.0 新增
rooms
<string>
|<string[]>
- 傳回
BroadcastOperator
設定後續事件發射的修改器,事件只會廣播給尚未加入指定 rooms
的用戶端。
// the "foo" event will be broadcast to all connected clients, except the ones that are in the "room-101" room
io.except("room-101").emit("foo", "bar");
// with an array of rooms
io.except(["room-101", "room-102"]).emit("foo", "bar");
// with multiple chained calls
io.except("room-101").except("room-102").emit("foo", "bar");
server.fetchSockets()
於 v4.0.0 新增
// return all Socket instances of the main namespace
const sockets = await io.fetchSockets();
// return all Socket instances in the "room1" room of the main namespace
const sockets = await io.in("room1").fetchSockets();
範例用法
io.on("connection", (socket) => {
const userId = computeUserId(socket);
socket.join(userId);
socket.on("disconnect", async () => {
const sockets = await io.in(userId).fetchSockets();
if (sockets.length === 0) {
// no more active connections for the given user
}
});
});
這個方法也可以在多個 Socket.IO 伺服器叢集中使用,搭配相容的轉接器,例如 Postgres 轉接器。
在這種情況下,如果你只想傳回指定節點上的 socket 實例,你需要使用 local
旗標
// return all Socket instances that are currently connected on the given node
const sockets = await io.local.fetchSockets();
請參閱 這裡。
server.in(room)
在 v1.0.0 中新增
server.to(room) 的同義詞,但在某些情況下可能更清楚
// disconnect all clients in the "room-101" room
io.in("room-101").disconnectSockets();
server.listen(httpServer[, options])
server.attach(httpServer[, options]) 的同義詞。
server.listen(port[, options])
server.attach(port[, options]) 的同義詞。
server.of(nsp)
nsp
<string>
|<RegExp>
|<Function>
- 傳回
<Namespace>
依據路徑名稱識別碼 nsp
初始化並擷取指定的 Namespace
。如果命名空間已初始化,它會立即傳回。
const adminNamespace = io.of("/admin");
也可以提供正則表示法或函數,以動態方式建立命名空間
const dynamicNsp = io.of(/^\/dynamic-\d+$/).on("connection", (socket) => {
const newNamespace = socket.nsp; // newNamespace.name === "/dynamic-101"
// broadcast to all clients in the given sub-namespace
newNamespace.emit("hello");
});
// client-side
const socket = io("/dynamic-101");
// broadcast to all clients in each sub-namespace
dynamicNsp.emit("hello");
// use a middleware for each sub-namespace
dynamicNsp.use((socket, next) => { /* ... */ });
使用函數
io.of((name, query, next) => {
// the checkToken method must return a boolean, indicating whether the client is able to connect or not.
next(null, checkToken(query.token));
}).on("connection", (socket) => { /* ... */ });
server.on(eventName, listener)
繼承自 EventEmitter 類別。
eventName
<string>
|<symbol>
listener
<Function>
- 傳回
<Server>
將 listener
函數新增到名為 eventName
事件的 listeners 陣列尾端。
可用的事件
connection
new_namespace
- 來自
serverSideEmit
方法的任何自訂事件
io.on("connection", (socket) => {
// ...
});
server.onconnection(socket)
socket
<engine.Socket>
- 傳回
<Server>
僅限進階使用。從傳入的 engine.io (或相容的 API) Socket
建立新的 socket.io
伺服器端。
import { Server } from "socket.io";
import { Server as Engine } from "engine.io";
const engine = new Engine();
const io = new Server();
engine.on("connection", (socket) => {
io.onconnection(socket);
});
engine.listen(3000);
server.path([value])
設定 value
路徑,engine.io
和靜態檔案會在該路徑下提供服務。預設為 /socket.io/
。如果未提供任何參數,此方法會傳回目前的值。
import { Server } from "socket.io";
const io = new Server();
io.path("/myownpath/");
path
值必須與客戶端側的值相符
import { io } from "socket.io-client";
const socket = io({
path: "/myownpath/"
});
server.serveClient([value])
如果 value
為 true
,附加的伺服器將提供客戶端檔案。預設為 true
。呼叫 listen
之後,此方法無效。如果未提供任何參數,此方法會傳回目前值。
import { Server } from "socket.io";
const io = new Server();
io.serveClient(false);
io.listen(3000);
server.serverSideEmit(eventName[, ...args][, ack])
新增於 v4.1.0
別名為:io.of("/").serverSideEmit(/* ... */);
eventName
<string>
args
<any[]>
ack
<Function>
- 傳回
true
傳送訊息至 叢集 中的其他 Socket.IO 伺服器。
語法
io.serverSideEmit("hello", "world");
在接收端
io.on("hello", (arg1) => {
console.log(arg1); // prints "world"
});
也支援確認。
// server A
io.serverSideEmit("ping", (err, responses) => {
console.log(responses[0]); // prints "pong"
});
// server B
io.on("ping", (cb) => {
cb("pong");
});
注意事項
connection
、connect
和new_namespace
字串是保留字,應用程式中不能使用。可以傳送任意數量的參數,但目前不支援二進制結構(參數陣列會執行
JSON.stringify
)。
範例
io.serverSideEmit("hello", "world", 1, "2", { 3: "4" });
- 如果其他 Socket.IO 伺服器在指定延遲後沒有回應,確認回呼可能會呼叫錯誤。
io.serverSideEmit("ping", (err, responses) => {
if (err) {
// at least one Socket.IO server has not responded
// the 'responses' array contains all the responses already received though
} else {
// success! the 'responses' array contains one object per other Socket.IO server in the cluster
}
});
server.serverSideEmitWithAck(eventName[, ...args])
在 v4.6.0 中新增
別名為:io.of("/").serverSideEmitWithAck(/* ... */);
eventName
<string>
args
<any[]>
ack
<Function>
- 傳回
Promise<any[]>
廣播和預期來自 叢集 中的其他 Socket.IO 伺服器確認的版本。
try {
const responses = await io.serverSideEmitWithAck("some-event");
console.log(responses); // one response per server (except itself)
} catch (e) {
// some servers did not acknowledge the event in the given delay
}
上述範例等同於
io.serverSideEmit("some-event", (err, responses) => {
if (err) {
// some servers did not acknowledge the event in the given delay
} else {
console.log(responses); // one response per server (except itself)
}
});
在接收端
io.on("some-event", (callback) => {
callback("got it"); // only one argument is expected
});
server.socketsJoin(rooms)
於 v4.0.0 新增
別名為 io.of("/").socketsJoin(rooms)
。
// make all Socket instances join the "room1" room
io.socketsJoin("room1");
// make all Socket instances in the "room1" room join the "room2" and "room3" rooms
io.in("room1").socketsJoin(["room2", "room3"]);
// this also works with a single socket ID
io.in(theSocketId).socketsJoin("room1");
這個方法也可以在多個 Socket.IO 伺服器叢集中使用,搭配相容的轉接器,例如 Postgres 轉接器。
在這種情況下,如果你只想影響給定節點上的 socket 實例,你需要使用 local
旗標
// make all Socket instances that are currently connected on the given node join the "room1" room
io.local.socketsJoin("room1");
請參閱 這裡。
server.socketsLeave(rooms)
於 v4.0.0 新增
別名為 io.of("/").socketsLeave(rooms)
。
// make all Socket instances leave the "room1" room
io.socketsLeave("room1");
// make all Socket instances in the "room1" room leave the "room2" and "room3" rooms
io.in("room1").socketsLeave(["room2", "room3"]);
// this also works with a single socket ID
io.in(theSocketId).socketsLeave("room1");
這個方法也可以在多個 Socket.IO 伺服器叢集中使用,搭配相容的轉接器,例如 Postgres 轉接器。
在這種情況下,如果你只想影響給定節點上的 socket 實例,你需要使用 local
旗標
// make all Socket instances that are currently connected on the given node leave the "room1" room
io.local.socketsLeave("room1");
請參閱 這裡。
server.timeout(value)
在 v4.5.0 中新增
value
<number>
- 傳回
BroadcastOperator
設定後續事件發射的修改器,當給定的毫秒數經過後,仍未收到所有目標客戶端的確認時,回呼會帶有錯誤訊息呼叫
io.timeout(10000).emit("some-event", (err, responses) => {
if (err) {
// some clients did not acknowledge the event in the given delay
} else {
console.log(responses); // one response per client
}
});
server.to(room)
歷史
版本 | 變更 |
---|---|
v4.0.0 | 允許傳遞房間陣列。 |
v1.0.0 | 初始實作。 |
room
<string>
|<string[]>
- 傳回
BroadcastOperator
以進行串接
設定後續事件發射的修改器,事件將僅廣播給已加入給定 room
的客戶端。
若要發射到多個房間,您可以多次呼叫 to
。
// the “foo” event will be broadcast to all connected clients in the “room-101” room
io.to("room-101").emit("foo", "bar");
// with an array of rooms (a client will be notified at most once)
io.to(["room-101", "room-102"]).emit("foo", "bar");
// with multiple chained calls
io.to("room-101").to("room-102").emit("foo", "bar");
server.use(fn)
在 v1.0.0 中新增
io.of("/").use(fn)
的別名。
fn
<Function>
註冊主命名空間的中介軟體,這是一個針對每個傳入 Socket
執行的函式,並接收 socket 和一個函式,以選擇性地將執行遞延到下一個註冊的中介軟體。
傳遞給中介軟體回呼的錯誤會以特殊 connect_error
封包傳送給客戶端。
伺服器
io.use((socket, next) => {
const err = new Error("not authorized");
err.data = { content: "Please retry later" }; // additional details
next(err);
});
客戶端
socket.on("connect_error", err => {
console.log(err instanceof Error); // true
console.log(err.message); // not authorized
console.log(err.data); // { content: "Please retry later" }
});
更多資訊請見 此處。
如果您正在尋找 Express 中介軟體,請查看 此區段。
命名空間


表示在由路徑名稱(例如:/chat
)識別的特定範圍下連接的 socket 池。
更多資訊請見 此處。
屬性
namespace.adapter
命名空間使用的 "Adapter"。
注意:主命名空間的轉接器可以使用 io.of("/").adapter
存取。
關於它的更多資訊 在此。
const adapter = io.of("/my-namespace").adapter;
namespace.name
命名空間識別器屬性。
namespace.sockets
連線到這個命名空間的 Socket 實例的對應表。
// number of sockets in this namespace (on this node)
const socketCount = io.of("/admin").sockets.size;
事件
事件:'connect'
同義詞 事件:'connection'。
事件:'connection'
socket
<Socket>
於與客戶端建立連線時觸發。
// main namespace
io.on("connection", (socket) => {
// ...
});
// custom namespace
io.of("/admin").on("connection", (socket) => {
// ...
});
方法
namespace.allSockets()
- 傳回
Promise<Set<SocketId>>
這個方法將在下一版主要版本中移除,請改用 serverSideEmit()
或 fetchSockets()
。
取得連線到這個命名空間的 Socket ID 清單(如果適用,會跨所有節點)。
// all sockets in the main namespace
const ids = await io.allSockets();
// all sockets in the main namespace and in the "user:1234" room
const ids = await io.in("user:1234").allSockets();
// all sockets in the "chat" namespace
const ids = await io.of("/chat").allSockets();
// all sockets in the "chat" namespace and in the "general" room
const ids = await io.of("/chat").in("general").allSockets();
namespace.disconnectSockets([close])
於 v4.0.0 新增
close
<布林>
是否關閉底層連線- 傳回
void
讓相符的 Socket 實例斷線。
// make all Socket instances disconnect
io.disconnectSockets();
// make all Socket instances in the "room1" room disconnect (and discard the low-level connection)
io.in("room1").disconnectSockets(true);
// make all Socket instances in the "room1" room of the "admin" namespace disconnect
io.of("/admin").in("room1").disconnectSockets();
// this also works with a single socket ID
io.of("/admin").in(theSocketId).disconnectSockets();
namespace.emit(eventName[, ...args])
歷史
版本 | 變更 |
---|---|
v4.5.0 | io.emit() 現在支援確認。 |
v1.0.0 | 初始實作。 |
對給定命名空間中所有已連線的用戶端發出事件。
io.of("/chat").emit("hello");
可以包含任意數量的參數,並且支援所有可序列化的資料結構
io.of("/chat").emit("hello", 1, "2", { "3": 4 }, Buffer.from([5]));
在接收端
socket.on("hello", (arg1, arg2, arg3, arg4) => {
console.log(arg1); // 1
console.log(arg2); // "2"
console.log(arg3); // { "3": 4 }
console.log(arg4); // ArrayBuffer or Buffer, depending on the platform
});
參數會自動序列化,因此不需要呼叫 JSON.stringify()
。
你可以使用 to()
和 except()
將封包傳送給特定用戶端
// the “hello” event will be broadcast to all connected clients that are either
// in the "room1" room or in the "room2" room, excluding those in the "room3" room
io.of("/chat").to("room1").to("room2").except("room3").emit("hello");
從版本 4.5.0
開始,現在可以在廣播時使用確認
io.of("/chat").timeout(10000).emit("some-event", (err, responses) => {
if (err) {
// some clients did not acknowledge the event in the given delay
} else {
console.log(responses); // one response per client
}
});
在這種情況下,呼叫 timeout()
是必要的。
namespace.emitWithAck(eventName[, ...args])
在 v4.6.0 中新增
eventName
<string>
|<symbol>
args
any[]
- 傳回
Promise<any[]>
基於 Promise 的廣播版本,並期待給定命名空間中所有目標用戶端的確認
try {
const responses = await io.of("/chat").timeout(10000).emitWithAck("some-event");
console.log(responses); // one response per client
} catch (e) {
// some clients did not acknowledge the event in the given delay
}
上述範例等同於
io.of("/chat").timeout(10000).emit("some-event", (err, responses) => {
if (err) {
// some clients did not acknowledge the event in the given delay
} else {
console.log(responses); // one response per client
}
});
在接收端
socket.on("some-event", (callback) => {
callback("got it"); // only one argument is expected
});
namespace.except(rooms)
於 v4.0.0 新增
rooms
<string>
|<string[]>
- 傳回
BroadcastOperator
設定後續事件發射的修改器,事件只會廣播給尚未加入指定 rooms
的用戶端。
const myNamespace = io.of("/my-namespace");
// the "foo" event will be broadcast to all connected clients, except the ones that are in the "room-101" room
myNamespace.except("room-101").emit("foo", "bar");
// with an array of rooms
myNamespace.except(["room-101", "room-102"]).emit("foo", "bar");
// with multiple chained calls
myNamespace.except("room-101").except("room-102").emit("foo", "bar");
namespace.fetchSockets()
於 v4.0.0 新增
- 傳回
Socket[]
|RemoteSocket[]
傳回相符的 Socket 實例
// return all Socket instances in the main namespace
const sockets = await io.fetchSockets();
// return all Socket instances in the "room1" room of the main namespace
const sockets = await io.in("room1").fetchSockets();
// return all Socket instances in the "room1" room of the "admin" namespace
const sockets = await io.of("/admin").in("room1").fetchSockets();
// this also works with a single socket ID
const sockets = await io.in(theSocketId).fetchSockets();
上述範例中的 sockets
變數是一個物件陣列,公開 Socket 類別的子集
for (const socket of sockets) {
console.log(socket.id);
console.log(socket.handshake);
console.log(socket.rooms);
console.log(socket.data);
socket.emit(/* ... */);
socket.join(/* ... */);
socket.leave(/* ... */);
socket.disconnect(/* ... */);
}
data
屬性是一個任意物件,可供 Socket.IO 伺服器之間共用資訊
// server A
io.on("connection", (socket) => {
socket.data.username = "alice";
});
// server B
const sockets = await io.fetchSockets();
console.log(sockets[0].data.username); // "alice"
重要事項:此方法(以及 socketsJoin
、socketsLeave
和 disconnectSockets
)與 Redis 介面相容(從 socket.io-redis@6.1.0
開始),意即它們可以在 Socket.IO 伺服器之間運作。
namespace.in(room)
在 v1.0.0 中新增
namespace.to(room) 的同義詞,但在某些情況下可能會更清楚
const myNamespace = io.of("/my-namespace");
// disconnect all clients in the "room-101" room
myNamespace.in("room-101").disconnectSockets();
namespace.serverSideEmit(eventName[, ...args][, ack])
新增於 v4.1.0
eventName
<string>
args
<any[]>
ack
<Function>
- 傳回
true
傳送訊息至 叢集 中的其他 Socket.IO 伺服器。
語法
io.of("/chat").serverSideEmit("hello", "world");
在接收端
io.of("/chat").on("hello", (arg1) => {
console.log(arg1); // prints "world"
});
也支援確認。
// server A
io.of("/chat").serverSideEmit("ping", (err, responses) => {
console.log(responses[0]); // prints "pong"
});
// server B
io.of("/chat").on("ping", (cb) => {
cb("pong");
});
注意事項
connection
、connect
和new_namespace
字串是保留字,應用程式中不能使用。可以傳送任意數量的參數,但目前不支援二進制結構(參數陣列會執行
JSON.stringify
)。
範例
io.of("/chat").serverSideEmit("hello", "world", 1, "2", { 3: "4" });
- 如果其他 Socket.IO 伺服器在指定延遲後沒有回應,確認回呼可能會呼叫錯誤。
io.of("/chat").serverSideEmit("ping", (err, responses) => {
if (err) {
// at least one Socket.IO server has not responded
// the 'responses' array contains all the responses already received though
} else {
// success! the 'responses' array contains one object per other Socket.IO server in the cluster
}
});
namespace.serverSideEmitWithAck(eventName[, ...args])
在 v4.6.0 中新增
eventName
<string>
args
<any[]>
ack
<Function>
- 傳回
Promise<any[]>
廣播和預期來自 叢集 中的其他 Socket.IO 伺服器確認的版本。
try {
const responses = await io.of("/chat").serverSideEmitWithAck("some-event");
console.log(responses); // one response per server (except itself)
} catch (e) {
// some servers did not acknowledge the event in the given delay
}
上述範例等同於
io.of("/chat").serverSideEmit("some-event", (err, responses) => {
if (err) {
// some servers did not acknowledge the event in the given delay
} else {
console.log(responses); // one response per server (except itself)
}
});
在接收端
io.of("/chat").on("some-event", (callback) => {
callback("got it"); // only one argument is expected
});
namespace.socketsJoin(rooms)
於 v4.0.0 新增
rooms
<string>
|<string[]>
- 傳回
void
讓相符的 Socket 實例加入指定的房間
// make all Socket instances join the "room1" room
io.socketsJoin("room1");
// make all Socket instances in the "room1" room join the "room2" and "room3" rooms
io.in("room1").socketsJoin(["room2", "room3"]);
// make all Socket instances in the "room1" room of the "admin" namespace join the "room2" room
io.of("/admin").in("room1").socketsJoin("room2");
// this also works with a single socket ID
io.in(theSocketId).socketsJoin("room1");
更多資訊請參閱此處。
namespace.socketsLeave(rooms)
於 v4.0.0 新增
rooms
<string>
|<string[]>
- 傳回
void
讓相符的 Socket 實例離開指定的房間
// make all Socket instances leave the "room1" room
io.socketsLeave("room1");
// make all Socket instances in the "room1" room leave the "room2" and "room3" rooms
io.in("room1").socketsLeave(["room2", "room3"]);
// make all Socket instances in the "room1" room of the "admin" namespace leave the "room2" room
io.of("/admin").in("room1").socketsLeave("room2");
// this also works with a single socket ID
io.in(theSocketId).socketsLeave("room1");
namespace.timeout(value)
在 v4.5.0 中新增
value
<number>
- 傳回
BroadcastOperator
設定後續事件發射的修改器,當超過給定的毫秒數,且未收到客戶端的確認時,會呼叫回呼並傳回錯誤訊息
io.of("/chat").timeout(10000).emit("some-event", (err, responses) => {
if (err) {
// some clients did not acknowledge the event in the given delay
} else {
console.log(responses); // one response per client
}
});
namespace.to(room)
歷史
版本 | 變更 |
---|---|
v4.0.0 | 允許傳遞房間陣列。 |
v1.0.0 | 初始實作。 |
room
<string>
|<string[]>
- 傳回
BroadcastOperator
以進行串接
設定後續事件發射的修改器,事件將僅廣播給已加入給定 room
的客戶端。
若要發射到多個房間,您可以多次呼叫 to
。
const myNamespace = io.of("/my-namespace");
// the “foo” event will be broadcast to all connected clients in the “room-101” room
myNamespace.to("room-101").emit("foo", "bar");
// with an array of rooms (a client will be notified at most once)
myNamespace.to(["room-101", "room-102"]).emit("foo", "bar");
// with multiple chained calls
myNamespace.to("room-101").to("room-102").emit("foo", "bar");
namespace.use(fn)
在 v1.0.0 中新增
fn
<Function>
為指定的命名空間註冊中間件,這是一個針對每個傳入 Socket
執行的函式,並接收 Socket 和一個函式作為參數,以選擇性地將執行遞延到下一個註冊的中間件。
傳遞給中介軟體回呼的錯誤會以特殊 connect_error
封包傳送給客戶端。
伺服器
io.of("/chat").use((socket, next) => {
const err = new Error("not authorized");
err.data = { content: "Please retry later" }; // additional details
next(err);
});
客戶端
socket.on("connect_error", err => {
console.log(err instanceof Error); // true
console.log(err.message); // not authorized
console.log(err.data); // { content: "Please retry later" }
});
更多資訊請見 此處。
如果您正在尋找 Express 中介軟體,請查看 此區段。
旗標
旗標:'local'
設定後續事件發射的修改器,事件資料將只會廣播到目前的節點(當擴充到多個節點時)。
io.local.emit("an event", { some: "data" });
旗標:'volatile'
設定後續事件發射的修改器,如果用戶端尚未準備好接收訊息(因為網路速度過慢或其他問題,或因為透過長輪詢連線且正在進行要求回應循環),則事件資料可能會遺失。
io.volatile.emit("an event", { some: "data" }); // the clients may or may not receive it
Socket


Socket
是與瀏覽器用戶端互動的基本類別。Socket
屬於特定 Namespace
(預設為 /
),並使用底層 Client
進行通訊。
請注意,Socket
與實際的底層 TCP/IP socket
無直接關係,它只是類別的名稱。
在每個 Namespace
內,您也可以定義 Socket
可以加入和離開的任意頻道(稱為 room
)。這提供了一種方便的方式來廣播至一群 Socket
(請參閱下方的 Socket#to
)。
Socket
類別繼承自 EventEmitter。Socket
類別會覆寫 emit
方法,且不會修改任何其他 EventEmitter
方法。所有在此記錄但同時也顯示為 EventEmitter
方法(除了 emit
)的方法均由 EventEmitter
實作,且 EventEmitter
的文件適用。
更多資訊請參閱 此處。
事件
事件:'disconnect'
reason
<string>
斷線原因(用戶端或伺服器端)
斷線時觸發。
io.on("connection", (socket) => {
socket.on("disconnect", (reason) => {
// ...
});
});
可能原因
原因 | 說明 |
---|---|
伺服器命名空間斷線 | 使用 socket.disconnect() 強制斷開 Socket 連線。 |
用戶端命名空間斷線 | 用戶端已使用 socket.disconnect() 手動斷開 Socket 連線。 |
伺服器關閉 | 伺服器正在關閉。 |
ping 超時 | 用戶端未在 pingTimeout 延遲時間內傳送 PONG 封包。 |
傳輸關閉 | 連線已關閉(範例:使用者已失去連線,或網路已從 WiFi 變更為 4G)。 |
傳輸錯誤 | 連線遇到錯誤。 |
解析錯誤 | 伺服器收到來自用戶端無效的封包。 |
強制關閉 | 伺服器收到來自用戶端無效的封包。 |
強制伺服器關閉 | 用戶端沒有及時加入命名空間(請參閱 connectTimeout 選項),並被強制關閉。 |
事件:'disconnecting'
在 v1.5.0 中新增
reason
<string>
斷線原因(用戶端或伺服器端)
當用戶端即將斷線(但尚未離開其 rooms
)時觸發。
io.on("connection", (socket) => {
socket.on("disconnecting", (reason) => {
console.log(socket.rooms); // Set { ... }
});
});
使用非同步處理程序時,您需要建立 rooms
屬性的副本
io.on("connection", (socket) => {
socket.on("disconnecting", async (reason) => {
const rooms = new Set(socket.rooms);
await someLongRunningOperation();
// socket.rooms will be empty there
console.log(rooms);
});
});
這些事件,連同 connect
、connect_error
、newListener
和 removeListener
,是特殊事件,不應在您的應用程式中使用
// BAD, will throw an error
socket.emit("disconnect");
屬性
socket.client
對應的 Client
物件參考。
socket.conn
<engine.Socket>
對應的 Client
傳輸連線(engine.io Socket
物件)。這允許存取 IO 傳輸層,它仍然(大多數)抽象化實際的 TCP/IP socket。
io.on("connection", (socket) => {
console.log("initial transport", socket.conn.transport.name); // prints "polling"
socket.conn.once("upgrade", () => {
// called when the transport is upgraded (i.e. from HTTP long-polling to WebSocket)
console.log("upgraded transport", socket.conn.transport.name); // prints "websocket"
});
socket.conn.on("packet", ({ type, data }) => {
// called for each packet received
});
socket.conn.on("packetCreate", ({ type, data }) => {
// called for each packet sent
});
socket.conn.on("drain", () => {
// called when the write buffer is drained
});
socket.conn.on("close", (reason) => {
// called when the underlying connection is closed
});
});
socket.data
於 v4.0.0 新增
一個任意物件,可與 fetchSockets()
實用程式方法結合使用
io.on("connection", (socket) => {
socket.data.username = "alice";
});
const sockets = await io.fetchSockets();
console.log(sockets[0].data.username); // "alice"
這也適用於 Socket.IO 叢集,並搭配相容的轉接器,例如 Postgres 轉接器。
socket.handshake
握手詳細資料
欄位 | 類型 | 說明 |
---|---|---|
headers | IncomingHttpHeaders | 作為握手一部分傳送的標頭。 |
time | <字串> | 建立日期(字串格式)。 |
address | <字串> | 用戶端的 IP 位址。 |
xdomain | <boolean> | 連線是否跨網域。 |
secure | <boolean> | 連線是否透過 SSL 建立。 |
issued | <number> | 建立日期(Unix 時間戳記格式)。 |
url | <字串> | 請求 URL 字串。 |
query | Record<string, string or string[]> | 第一個請求的查詢參數。 |
auth | Record<string, any> | 驗證負載。另請參閱這裡。 |
用法
io.use((socket, next) => {
let handshake = socket.handshake;
// ...
});
io.on("connection", (socket) => {
let handshake = socket.handshake;
// ...
});
範例
const handshake = {
headers: {
"user-agent": "node-XMLHttpRequest",
accept: "*/*",
host: "localhost:3000",
connection: "close"
},
time: "Wed Jan 01 2020 01:00:00 GMT+0100 (Central European Standard Time)",
address: "::ffff:127.0.0.1",
xdomain: false,
secure: false,
issued: 1577836800000,
url: "/socket.io/?EIO=4&transport=polling&t=OPAfXv5&b64=1",
query: {
EIO: "4",
transport: "polling",
t: "OPAfXv5",
b64: "1"
},
auth: {}
}
注意:headers
屬性是指階段的第一個 HTTP 請求的標頭,不會由後續的 HTTP 請求更新。
io.on("connection", (socket) => {
console.log(socket.handshake.headers === socket.request.headers); // prints "true"
});
socket.id
階段的唯一識別碼,來自底層的 Client
。
id
屬性是一個短暫的 ID,不應在您的應用程式中使用(或僅用於除錯目的),因為
- 此 ID 會在每次重新連線後重新產生(例如,當 WebSocket 連線中斷,或當使用者重新整理頁面時)
- 兩個不同的瀏覽器分頁會有兩個不同的 ID
- 伺服器上沒有為特定 ID 儲存訊息佇列(即如果用戶端斷線,伺服器傳送至該 ID 的訊息將會遺失)
請改用一般階段 ID(透過 Cookie 傳送,或儲存在 localStorage 中並在auth
負載中傳送)。
另請參閱
socket.recovered
在 v4.6.0 中新增
在上次重新連線期間,連線狀態是否成功復原。
io.on("connection", (socket) => {
if (socket.recovered) {
// recovery was successful: socket.id, socket.rooms and socket.data were restored
} else {
// new or unrecoverable session
}
});
關於此功能的更多資訊,請按這裡。
socket.request
取得參考的代理,傳回產生底層 engine.io Client
的 request
。對於存取請求標頭(例如 Cookie
或 User-Agent
)很有用。
import { parse } from "cookie";
io.on("connection", (socket) => {
const cookies = parse(socket.request.headers.cookie || "");
});
注意:socket.request
指的是階段的第一個 HTTP 請求,不會由後續的 HTTP 請求更新。
io.on("connection", (socket) => {
console.log(socket.request.headers === socket.handshake.headers); // prints "true"
});
如果您不需要此參考,可以捨棄它以減少記憶體使用量
io.on("connection", (socket) => {
delete socket.conn.request;
});
socket.rooms
一組識別此用戶端所在房間的字串。
io.on("connection", (socket) => {
console.log(socket.rooms); // Set { <socket.id> }
socket.join("room1");
console.log(socket.rooms); // Set { <socket.id>, "room1" }
});
方法
socket.compress(value)
value
<boolean>
是否將後續封包壓縮- 傳回
Socket
以串連
設定後續事件發射的修改器,表示僅在值為 true
時才會壓縮事件資料。未呼叫此方法時,預設為 true
。
io.on("connection", (socket) => {
socket.compress(false).emit("uncompressed", "that's rough");
});
socket.disconnect([close])
中斷此 socket。若 close 的值為 true
,則關閉底層連線。否則,僅中斷命名空間。
io.on("connection", (socket) => {
setTimeout(() => socket.disconnect(true), 5000);
});
socket.emit(eventName[, ...args][, ack])
(覆寫 EventEmitter.emit
)
eventName
<string>
|<symbol>
args
<any[]>
ack
<Function>
- 傳回
true
發射事件至由字串名稱識別的 socket。可包含任何其他參數。支援所有可序列化資料結構,包括 Buffer
。
io.on("connection", () => {
socket.emit("hello", "world");
socket.emit("with-binary", 1, "2", { 3: "4", 5: Buffer.from([6]) });
});
ack
參數為選用,且會呼叫客戶端的回應。
伺服器
io.on("connection", (socket) => {
socket.emit("hello", "world", (response) => {
console.log(response); // "got it"
});
});
客戶端
socket.on("hello", (arg, callback) => {
console.log(arg); // "world"
callback("got it");
});
socket.emitWithAck(eventName[, ...args])
在 v4.6.0 中新增
eventName
<string>
|<symbol>
args
any[]
- 傳回
Promise<any>
發射並期待來自指定客戶端確認的 Promise 版本
io.on("connection", async (socket) => {
// 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 client did not acknowledge the event in the given delay
}
});
上述範例等同於
io.on("connection", (socket) => {
// without timeout
socket.emit("hello", "world", (val) => {
// ...
});
// with a specific timeout
socket.timeout(10000).emit("hello", "world", (err, val) => {
// ...
});
});
在接收端
socket.on("hello", (arg1, callback) => {
callback("got it"); // only one argument is expected
});
socket.eventNames()
繼承自 EventEmitter
(以及其他未在此處提及的方法)。請參閱 Node.js 文件中的 事件 模組。
socket.except(rooms)
於 v4.0.0 新增
rooms
<string>
|<string[]>
- 傳回
BroadcastOperator
設定後續事件發射的修改器,表示僅會廣播事件至尚未加入指定 rooms
的客戶端(不包含 socket 本身)。
// to all clients except the ones in "room1" and the sender
socket.broadcast.except("room1").emit(/* ... */);
// same as above
socket.except("room1").emit(/* ... */);
// to all clients in "room4" except the ones in "room5" and the sender
socket.to("room4").except("room5").emit(/* ... */);
socket.in(room)
在 v1.0.0 中新增
socket.to(room) 的同義詞。
socket.join(room)
room
<string>
|<string[]>
- 傳回
void
|Promise
將 socket 加入指定的 room
或加入房間清單。
io.on("connection", (socket) => {
socket.join("room 237");
console.log(socket.rooms); // Set { <socket.id>, "room 237" }
socket.join(["room 237", "room 238"]);
io.to("room 237").emit("a new user has joined the room"); // broadcast to everyone in the room
});
加入房間的機制由已設定的 Adapter
處理(請參閱上方的 Server#adapter
),預設為 socket.io-adapter。
為方便起見,每個 socket 會自動加入一個由其 id 識別的房間(請參閱 Socket#id
)。這讓廣播訊息給其他 socket 變得很容易
io.on("connection", (socket) => {
socket.on("say to someone", (id, msg) => {
// send a private message to the socket with the given id
socket.to(id).emit("my message", msg);
});
});
socket.leave(room)
room
<字串>
- 傳回
void
|Promise
從指定的 room
中移除 socket。
io.on("connection", (socket) => {
socket.leave("room 237");
io.to("room 237").emit(`user ${socket.id} has left the room`);
});
中斷連線後,會自動離開房間。
socket.listenersAny()
- 傳回
<函式陣列>
傳回已註冊的萬用監聽器清單。
const listeners = socket.listenersAny();
socket.listenersAnyOutgoing()
在 v4.5.0 中新增
- 傳回
<函式陣列>
傳回已註冊的萬用監聽器清單,用於傳送封包。
const listeners = socket.listenersAnyOutgoing();
socket.offAny([listener])
listener
<Function>
移除先前註冊的監聽器。如果未提供監聽器,則會移除所有萬用監聽器。
const myListener = () => { /* ... */ };
socket.onAny(myListener);
// then, later
socket.offAny(myListener);
socket.offAny();
socket.offAnyOutgoing([listener])
在 v4.5.0 中新增
listener
<Function>
移除先前註冊的監聽器。如果未提供監聽器,則會移除所有萬用監聽器。
const myListener = () => { /* ... */ };
socket.onAnyOutgoing(myListener);
// remove a single listener
socket.offAnyOutgoing(myListener);
// remove all listeners
socket.offAnyOutgoing();
socket.on(eventName, callback)
繼承自 EventEmitter 類別。
eventName
<string>
|<symbol>
callback
<Function>
- 傳回
<Socket>
為指定的事件註冊新的處理常式。
socket.on("news", (data) => {
console.log(data);
});
// with several arguments
socket.on("news", (arg1, arg2, arg3) => {
// ...
});
// or with acknowledgement
socket.on("news", (data, callback) => {
callback(0);
});
socket.onAny(callback)
callback
<Function>
註冊新的萬用監聽器。
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 中新增
callback
<Function>
註冊新的萬用監聽器,用於傳送封包。
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, listener)
繼承自 EventEmitter
(以及其他未在此處提及的方法)。請參閱 Node.js 文件中的 事件 模組。
socket.prependAny(callback)
callback
<Function>
註冊新的萬用監聽器。監聽器會新增到監聽器陣列的開頭。
socket.prependAny((event, ...args) => {
console.log(`got ${event}`);
});
socket.prependAnyOutgoing(callback)
在 v4.5.0 中新增
callback
<Function>
註冊新的萬用監聽器,用於傳送封包。監聽器會新增到監聽器陣列的開頭。
socket.prependAnyOutgoing((event, ...args) => {
console.log(`got ${event}`);
});
socket.removeAllListeners([eventName])
繼承自 EventEmitter
(以及其他未在此處提及的方法)。請參閱 Node.js 文件中的 事件 模組。
socket.removeListener(eventName, listener)
繼承自 EventEmitter
(以及其他未在此處提及的方法)。請參閱 Node.js 文件中的 事件 模組。
socket.send([...args][, ack])
args
<any[]>
ack
<Function>
- 傳回
Socket
傳送 訊息
事件。請參閱 socket.emit(eventName[, ...args][, ack])。
socket.timeout(value)
在 v4.4.0 中新增
設定後續事件發射的修改器,當超過給定的毫秒數,且未收到客戶端的確認時,會呼叫回呼並傳回錯誤訊息
socket.timeout(5000).emit("my-event", (err) => {
if (err) {
// the client did not acknowledge the event in the given delay
}
});
socket.to(room)
歷史
版本 | 變更 |
---|---|
v4.0.0 | 允許傳遞房間陣列。 |
v1.0.0 | 初始實作。 |
room
<string>
|<string[]>
- 傳回
Socket
以串連
設定後續事件發射的修改器,該事件將僅廣播給已加入指定 房間
的用戶端(不包括 socket 本身)。
若要發射到多個房間,您可以多次呼叫 to
。
io.on("connection", (socket) => {
// to one room
socket.to("others").emit("an event", { some: "data" });
// to multiple rooms
socket.to("room1").to("room2").emit("hello");
// or with an array
socket.to(["room1", "room2"]).emit("hello");
// a private message to another socket
socket.to(/* another socket id */).emit("hey");
// WARNING: `socket.to(socket.id).emit()` will NOT work
// Please use `io.to(socket.id).emit()` instead.
});
注意:廣播時不支援確認。
socket.use(fn)
歷史
版本 | 變更 |
---|---|
v3.0.5 | 還原為第一個實作。 |
v3.0.0 | 移除,改用 socket.onAny() 。 |
v1.7.2 | 錯誤 事件會直接傳送給用戶端。 |
v1.6.0 | 第一個實作。 |
fn
<Function>
註冊中間件,此為一個函式,會對每個傳入的 封包
執行,並接收封包和一個函式(可選擇將執行延後到下一個已註冊的中間件)。
傳遞給中間件回呼的錯誤會在伺服器端發射為 錯誤
事件
io.on("connection", (socket) => {
socket.use(([event, ...args], next) => {
if (isUnauthorized(event)) {
return next(new Error("unauthorized event"));
}
// do not forget to call next
next();
});
socket.on("error", (err) => {
if (err && err.message === "unauthorized event") {
socket.disconnect();
}
});
});
旗標
旗標:'broadcast'
設定後續事件發射的修改器,該事件資料將僅廣播給每個 socket,但不包括傳送者。
io.on("connection", (socket) => {
socket.broadcast.emit("an event", { some: "data" }); // everyone gets it but the sender
});
旗標:'volatile'
設定後續事件發射的修改器,如果用戶端尚未準備好接收訊息(因為網路速度慢或其他問題,或者因為他們透過長輪詢連線,且正在進行請求回應循環),則事件資料可能會遺失。
io.on("connection", (socket) => {
socket.volatile.emit("an event", { some: "data" }); // the client may or may not receive it
});
用戶端


用戶端
類別表示傳入傳輸(engine.io)連線。用戶端
可以與屬於不同 命名空間
的多工 Socket
產生關聯。
屬性
client.conn
<engine.Socket>
對應的 engine.io
Socket
連線參考。
client.request
取得產生 engine.io 連線的 請求
參考的 getter 代理。可用於存取請求標頭,例如 Cookie
或 User-Agent
。
引擎
Engine.IO 伺服器,管理 WebSocket / HTTP 長輪詢連線。更多資訊 在此。
其原始碼可以在這裡找到:https://github.com/socketio/engine.io
事件
事件:'connection_error'
新增於 v4.1.0
error
<Error>
io.engine.on("connection_error", (err) => {
console.log(err.req); // the request object
console.log(err.code); // the error code, for example 1
console.log(err.message); // the error message, for example "Session ID unknown"
console.log(err.context); // some additional error context
});
當連線異常關閉時,將會發出此事件。以下是可能的錯誤代碼清單
代碼 | 訊息 |
---|---|
0 | "傳輸不明" |
1 | "Session ID 不明" |
2 | "錯誤的握手方法" |
3 | "錯誤的請求" |
4 | "禁止" |
5 | "不支援的協定版本" |
事件:'headers'
新增於 v4.1.0
headers
<Object>
標頭雜湊,由標頭名稱索引request
<http.IncomingMessage>
輸入請求
此事件將在撰寫每個 HTTP 要求的回應標頭(包括 WebSocket 升級)之前發出,讓您可以自訂它們。
import { serialize, parse } from "cookie";
io.engine.on("headers", (headers, request) => {
if (!request.headers.cookie) return;
const cookies = parse(request.headers.cookie);
if (!cookies.randomId) {
headers["set-cookie"] = serialize("randomId", "abc", { maxAge: 86400 });
}
});
事件:'initial_headers'
新增於 v4.1.0
headers
<Object>
標頭雜湊,由標頭名稱索引request
<http.IncomingMessage>
輸入請求
此事件將在撰寫第一個 HTTP 要求(握手)的回應標頭之前發出,讓您可以自訂它們。
import { serialize } from "cookie";
io.engine.on("initial_headers", (headers, request) => {
headers["set-cookie"] = serialize("uid", "1234", { sameSite: "strict" });
});
如果您需要執行一些非同步操作,您將需要使用 allowRequest
選項
import { serialize } from "cookie";
const io = new Server(httpServer, {
allowRequest: async (req, callback) => {
const session = await fetchSession(req);
req.session = session;
callback(null, true);
}
});
io.engine.on("initial_headers", (headers, req) => {
if (req.session) {
headers["set-cookie"] = serialize("sid", req.session.id, { sameSite: "strict" });
}
});
另請參閱
屬性
engine.clientsCount
在 v1.0.0 中新增
目前連線的用戶端數量。
const count = io.engine.clientsCount;
// may or may not be similar to the count of Socket instances in the main namespace, depending on your usage
const count2 = io.of("/").sockets.size;
方法
engine.generateId
用於產生新的 Session ID 的函式。預設為 base64id。
const uuid = require("uuid");
io.engine.generateId = () => {
return uuid.v4(); // must be unique across all Socket.IO servers
}
engine.handleUpgrade(request, socket, head)
在 v1.0.0 中新增
request
<http.IncomingMessage>
輸入請求socket
<stream.Duplex>
伺服器與用戶端之間的網路 sockethead
<Buffer>
升級串流的第一個封包(可能為空)
此方法可用於注入 HTTP 升級
同時具有 Socket.IO 伺服器和平面 WebSocket 伺服器的範例
import { createServer } from "http";
import { Server as WsServer } from "ws";
import { Server } from "socket.io";
const httpServer = createServer();
const wss = new WsServer({ noServer: true });
const io = new Server(httpServer);
httpServer.removeAllListeners("upgrade");
httpServer.on("upgrade", (req, socket, head) => {
if (req.url === "/") {
wss.handleUpgrade(req, socket, head, (ws) => {
wss.emit("connection", ws, req);
});
} else if (req.url.startsWith("/socket.io/")) {
io.engine.handleUpgrade(req, socket, head);
} else {
socket.destroy();
}
});
httpServer.listen(3000);
engine.use(middleware)
在 v4.6.0 中新增
新增一個新的 Express 中介軟體。
io.engine.use((req, res, next) => {
// do something
next();
});
這些中介軟體會在每個傳入的 HTTP 要求中呼叫,包括升級要求。
使用 express-session
的範例
import session from "express-session";
io.engine.use(session({
secret: "keyboard cat",
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}));
使用 helmet
的範例
import helmet from "helmet";
io.engine.use(helmet());