Skip to main content
Version: 4.x

命名空间

命名空间是一种通信通道,允许你通过单个共享连接(也称为 "multiplexing")拆分应用的逻辑。

¥A Namespace is a communication channel that allows you to split the logic of your application over a single shared connection (also called "multiplexing").

Namespace diagramNamespace diagram

介绍

¥Introduction

每个命名空间都有自己的:

¥Each namespace has its own:

io.of("/orders").on("connection", (socket) => {
socket.on("order:list", () => {});
socket.on("order:create", () => {});
});

io.of("/users").on("connection", (socket) => {
socket.on("user:list", () => {});
});
const orderNamespace = io.of("/orders");

orderNamespace.on("connection", (socket) => {
socket.join("room1");
orderNamespace.to("room1").emit("hello");
});

const userNamespace = io.of("/users");

userNamespace.on("connection", (socket) => {
socket.join("room1"); // distinct from the room in the "orders" namespace
userNamespace.to("room1").emit("holà");
});
const orderNamespace = io.of("/orders");

orderNamespace.use((socket, next) => {
// ensure the socket has access to the "orders" namespace, and then
next();
});

const userNamespace = io.of("/users");

userNamespace.use((socket, next) => {
// ensure the socket has access to the "users" namespace, and then
next();
});

可能的用例:

¥Possible use cases:

  • 你想要创建一个只有授权用户才能访问的特殊命名空间,因此与这些用户相关的逻辑与应用的其余部分分开

    ¥you want to create a special namespace that only authorized users have access to, so the logic related to those users is separated from the rest of the application

const adminNamespace = io.of("/admin");

adminNamespace.use((socket, next) => {
// ensure the user has sufficient rights
next();
});

adminNamespace.on("connection", socket => {
socket.on("delete user", () => {
// ...
});
});
  • 你的应用有多个租户,因此你希望为每个租户动态创建一个命名空间

    ¥your application has multiple tenants so you want to dynamically create one namespace per tenant

const workspaces = io.of(/^\/\w+$/);

workspaces.on("connection", socket => {
const workspace = socket.nsp;

workspace.emit("hello");
});

主命名空间

¥Main namespace

到目前为止,你与名为 / 的主命名空间进行了交互。io 实例继承了它的所有方法:

¥Until now, you interacted with the main namespace, called /. The io instance inherits all of its methods:

io.on("connection", (socket) => {});
io.use((socket, next) => { next() });
io.emit("hello");
// are actually equivalent to
io.of("/").on("connection", (socket) => {});
io.of("/").use((socket, next) => { next() });
io.of("/").emit("hello");

有些教程可能还会提到 io.sockets,它只是 io.of("/") 的别名。

¥Some tutorials may also mention io.sockets, it's simply an alias for io.of("/").

io.sockets === io.of("/")

自定义命名空间

¥Custom namespaces

要设置自定义命名空间,可以在服务器端调用 of 函数:

¥To set up a custom namespace, you can call the of function on the server-side:

const nsp = io.of("/my-namespace");

nsp.on("connection", socket => {
console.log("someone connected");
});

nsp.emit("hi", "everyone!");

客户端初始化

¥Client initialization

同源版本:

¥Same-origin version:

const socket = io(); // or io("/"), the main namespace
const orderSocket = io("/orders"); // the "orders" namespace
const userSocket = io("/users"); // the "users" namespace

跨域/Node.js 版本:

¥Cross-origin/Node.js version:

const socket = io("https://example.com"); // or io("https://example.com/"), the main namespace
const orderSocket = io("https://example.com/orders"); // the "orders" namespace
const userSocket = io("https://example.com/users"); // the "users" namespace

在上面的示例中,只会建立一个 WebSocket 连接,数据包将自动路由到正确的命名空间。

¥In the example above, only one WebSocket connection will be established, and the packets will automatically be routed to the right namespace.

请注意,在以下情况下将禁用多路复用:

¥Please note that multiplexing will be disabled in the following cases:

  • 同一命名空间的多次创建

    ¥multiple creation for the same namespace

const socket1 = io();
const socket2 = io(); // no multiplexing, two distinct WebSocket connections
  • 不同字段

    ¥different domains

const socket1 = io("https://first.example.com");
const socket2 = io("https://second.example.com"); // no multiplexing, two distinct WebSocket connections
const socket1 = io();
const socket2 = io("/admin", { forceNew: true }); // no multiplexing, two distinct WebSocket connections

动态命名空间

¥Dynamic namespaces

还可以使用正则表达式动态创建名称空间:

¥It is also possible to dynamically create namespaces, either with a regular expression:

io.of(/^\/dynamic-\d+$/);

或者使用一个函数:

¥or with a function:

io.of((name, auth, next) => {
next(null, true); // or false, when the creation is denied
});

你可以在 connection 事件中访问新的命名空间:

¥You can have access to the new namespace in the connection event:

io.of(/^\/dynamic-\d+$/).on("connection", (socket) => {
const namespace = socket.nsp;
});

of() 方法的返回值就是我们所说的父命名空间,从中你可以:

¥The return value of the of() method is what we call the parent namespace, from which you can:

const parentNamespace = io.of(/^\/dynamic-\d+$/);

parentNamespace.use((socket, next) => { next() });

中间件将自动在每个子命名空间上注册。

¥The middleware will automatically be registered on each child namespace.

const parentNamespace = io.of(/^\/dynamic-\d+$/);

parentNamespace.emit("hello"); // will be sent to users in /dynamic-1, /dynamic-2, ...
caution

现有命名空间优先于动态命名空间。例如:

¥Existing namespaces have priority over dynamic namespaces. For example:

// register "dynamic-101" namespace
io.of("/dynamic-101");

io.of(/^\/dynamic-\d+$/).on("connection", (socket) => {
// will not be called for a connection on the "dynamic-101" namespace
});

完整的 API

¥Complete API

命名空间实例公开的完整 API 可以在 此处 中找到。

¥The complete API exposed by the Namespace instance can be found here.