Средние сервисы
Функция среднего сервиса — это функция, которая выполняется для каждого входящего соединения.
Функции среднего сервиса могут быть полезны для:
- ведения журнала
- аутентификации/авторизации
- лимитирования скорости
Примечание: эта функция будет выполнена только один раз на соединение (даже если соединение состоит из нескольких HTTP-запросов).
Регистрация среднего сервиса
Функция среднего сервиса имеет доступ к экземпляру Сокета и к следующей зарегистрированной функции среднего сервиса.
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(). В противном случае соединение будет зависнуть до его закрытия после заданного таймаута.
Важное примечание: экземпляр Сокета фактически не подключён, когда выполняется средний сервис, что означает, что ни одно событие 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
});
Вы можете добавить дополнительные сведения в объект 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 можно найти здесь.
© 2014–2021 Automattic
Licensed under the MIT License.
https://socket.io/docs/v4/middlewares