メインコンテンツへスキップ

express-session との連携方法

基本的なアプリケーションから始めましょう

const express = require("express");
const { createServer } = require("node:http");
const { join } = require("node:path");
const { Server } = require("socket.io");
const session = require("express-session");

const port = process.env.PORT || 3000;

const app = express();
const httpServer = createServer(app);

const sessionMiddleware = session({
secret: "changeit",
resave: true,
saveUninitialized: true,
});

app.use(sessionMiddleware);

app.get("/", (req, res) => {
res.sendFile(join(__dirname, "index.html"));
});

app.post("/incr", (req, res) => {
const session = req.session;
session.count = (session.count || 0) + 1;
res.status(200).end("" + session.count);
});

const io = new Server(httpServer);

httpServer.listen(port, () => {
console.log(`application is running at: http://localhost:${port}`);
});

セッションコンテキストの共有

セッションコンテキストは、次のコードを呼び出すことで Socket.IO サーバーと共有できます。

io.engine.use(sessionMiddleware);

このように簡単です!これで session オブジェクトにアクセスできるようになります

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

セッション ID の使用

セッション ID を使用して、Express と Socket.IO の間のリンクを作成できます。

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

// the session ID is used as a room
socket.join(sessionId);
});

次に、/incr ハンドラー内のすべての接続されたクライアントに通知できます。

app.post("/incr", (req, res) => {
const session = req.session;
session.count = (session.count || 0) + 1;
res.status(200).end("" + session.count);

io.to(session.id).emit("current count", session.count);
});

ログアウトフローも同様です

app.post("/logout", (req, res) => {
const sessionId = req.session.id;

req.session.destroy(() => {
// disconnect all Socket.IO connections linked to this session ID
io.in(sessionId).disconnectSockets();
res.status(204).end();
});
});

セッションの変更

単一の HTTP リクエストにバインドされていないため、セッションは手動でリロードおよび保存する必要があります

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

socket.on("my event", () => {
req.session.reload((err) => {
if (err) {
return socket.disconnect();
}
req.session.count++;
req.session.save();
});
});
});

また、受信パケットごとにトリガーされるミドルウェアを使用することもできます

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

socket.use((__, next) => {
req.session.reload((err) => {
if (err) {
socket.disconnect();
} else {
next();
}
});
});

// and then simply
socket.on("my event", () => {
req.session.count++;
req.session.save();
});
});
注意

req.session.reload() を呼び出すと、req.session オブジェクトが更新されます

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

socket.use((__, next) => {
session.reload(() => {
// WARNING! "session" still points towards the previous session object
});
});
});

セッションの有効期限の処理

セッションが期限切れになった場合(たとえば、クライアントが長期間イベントを送信しない場合)、セッションを定期的にリロードすることもできます

const SESSION_RELOAD_INTERVAL = 30 * 1000;

io.on("connection", (socket) => {
const timer = setInterval(() => {
socket.request.session.reload((err) => {
if (err) {
// forces the client to reconnect
socket.conn.close();
// you can also use socket.disconnect(), but in that case the client
// will not try to reconnect
}
});
}, SESSION_RELOAD_INTERVAL);

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

クロスサイトリクエストに関する注意

express-session は、ブラウザでセッションを永続化するために Cookie に依存しています。したがって、フロントエンドドメインがバックエンドドメインと異なる場合(たとえば、自分のマシンで実行されているが異なるポートにある SPA がある場合)、適切な CORS ヘッダーを送信する必要があります

const cors = require("cors");

const corsOptions = {
origin: ["http://localhost:4200"],
credentials: true
};

// for Express
app.use(cors(corsOptions));

// for Socket.IO
const io = new Server(httpServer, {
cors: corsOptions
});

また、クライアント側で withCredentials オプションを true に設定する必要があります

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

const socket = io("http://localhost:3000", {
withCredentials: true
});

以上が express-session との互換性に関する説明です。お読みいただきありがとうございます!

ヒント

この例をブラウザで直接実行できます