转到主要内容
Version: 4.x

中间件

中间件函数是为每个传入连接执行的函数。

中间件函数可用于:

  • logging
  • authentication / authorization
  • rate limiting

Note: this function will be executed only once per connection (even if the connection consists in multiple HTTP requests).

注册中间件

中间件函数可以访问Socket 实例和下一个注册的中间件函数。

io.use((socket, next) => {
if (isValid(socket.request)) {
next();
} else {
next(new Error("invalid"));
}
});

您可以注册几个中间件函数,它们将按顺序执行:

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

io.use((socket, next) => {
next(new Error("thou shall not pass"));
});

io.use((socket, next) => {
// not executed, since the previous middleware has returned an error
next();
});

请确保在任何情况下都调用next()。 否则,连接将一直挂起,直到在给定超时后关闭。

重要提示:执行中间件时,Socket 实例实际上并未连接,这意味着disconnect如果连接最终失败,则不会发出任何事件。

例如,如果客户端手动关闭连接:

// server-side
io.use((socket, next) => {
setTimeout(() => {
// next is called after the client disconnection
next();
}, 1000);

socket.on("disconnect", () => {
// not triggered
});
});

io.on("connection", (socket) => {
// not triggered
});

// client-side
const socket = io();
setTimeout(() => {
socket.disconnect();
}, 500);

发送凭据

auth客户端可以使用以下选项发送凭据:

// plain object
const socket = io({
auth: {
token: "abc"
}
});

// or with a function
const socket = io({
auth: (cb) => {
cb({
token: "abc"
});
}
});

可以在服务器端的握手对象中访问这些凭据:

io.use((socket, next) => {
const token = socket.handshake.auth.token;
// ...
});

处理中间件错误

如果next使用 Error 对象调用该方法,则连接将被拒绝并且客户端将收到一个connect_error事件。

// client-side
socket.on("connect_error", (err) => {
console.log(err.message); // prints the message associated with the error
});

您可以将其他详细信息附加到错误对象:

// server-side
io.use((socket, next) => {
const err = new Error("not authorized");
err.data = { content: "Please retry later" }; // additional details
next(err);
});

// client-side
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中间件的兼容性

大多数现有的Express 中间件模块应该与 Socket.IO 兼容,您只需要一个小包装函数来使方法签名匹配:

const wrap = middleware => (socket, next) => middleware(socket.request, {}, next);

结束请求-响应周期并且不调用的中间件函数next()将不起作用。

express-session示例:

const session = require("express-session");

io.use(wrap(session({ secret: "cats" })));

io.on("connection", (socket) => {
const session = socket.request.session;
});

Passport示例:

const session = require("express-session");
const passport = require("passport");

io.use(wrap(session({ secret: "cats" })));
io.use(wrap(passport.initialize()));
io.use(wrap(passport.session()));

io.use((socket, next) => {
if (socket.request.user) {
next();
} else {
next(new Error("unauthorized"))
}
});

可以在此处找到 Passport 的完整示例。