미들웨어와 소켓 연결하기
방에 입장할 때와 퇴장할 때 채팅방의 다른 사람에게 '#12C6B8님이 입장하였습니다' 같은 시스템 메시지를 초대하려고 합니다. 그런데 사용자의 이름은 세션(req.session.color)에 들어있습니다. socket.IO에서 세션에 접근하려면 추가 작업이 필요합니다.
Socket.IO도 미들웨어를 사용할 수 있으므로 express-session을 공유하면 됩니다. 추가로 채팅방 접속자가 0명일 때 제거하는 코드도 같이 넣어보겠습니다.
const express = require("express");
const path = require("path");
const cookieParser = require("cookie-parser");
const session = require("express-session");
const nunjucks = require("nunjucks");
const dotenv = require("dotenv");
const ColorHash = require("color-hash");
dotenv.config();
const webSocket = require("./socket");
const indexRouter = require("./routes");
const morgan = require("morgan");
const connect = require("./schemas");
const ColorHash = require("color-hash");
const app = express();
app.set("port", process.env.PORT || 8005);
app.set("view engine", "html");
nunjucks.configure("views", {
express: app,
watch: true,
});
connect();
const sessionMiddleware = session({
resave: false,
saveUninitialized: false,
secret: process.env.COOKIE_SECRET,
cookie: {
httpOnly: true,
secure: false,
},
});
app.use(morgan("dev"));
app.use(express.static(path.join(__dirname, "public")));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(sessionMiddleware);
app.use(
session({
resave: false,
saveUninitialized: false,
secret: process.env.COOKIE_SECRET,
cookie: {
httpOnly: true,
secure: false,
},
}),
);
app.use((req, res, next) => {
if (!req.session.color) {
const colorHash = new ColorHash();
req.session.color = colorHash.hex(req.sessionID);
}
next();
});
app.use("/", indexRouter);
app.use((req, res, next) => {
const error = new Error(`${req.method} ${req.url} 라우터가 없습니다.`);
error.status = 404;
next(error);
});
app.use((err, req, res, next) => {
res.locals.message = err.message;
res.locals.error = process.env.NODE_ENV !== "production" ? err : {};
res.status(err.status || 500);
res.render("error");
});
const server = app.listen(app.get("port"), () => {
console.log(app.get("port"), "번 포트에서 대기 중");
});
webSocket(server, app, sessionMiddleware);
app.js와 socket.js 간에 express-session 미들웨어를 공유하기 위해 변수로 분리했습니다.
socket.js와 다음과 같이 수정합니다.
const SocketIO = require("socket.io");
const axios = require("axios");
module.exports = (server, app, sessionMiddleware) => {
const io = SocketIO(server, { path: "/socket.io" });
app.set("io", io);
const room = io.of("/room");
const chat = io.of("/chat");
io.use((socket, next) => { // ❶
sessionMiddleware(socket.request, socket.request.res, next);
});
room.on("connection", (socket) => {
console.log("room 네임스페이스에 접속");
socket.on("disconnect", () => {
console.log("room 네임스페이스 접속 해제");
});
});
chat.on("connection", (socket) => {
console.log("chat 네임스페이스 접속");
const req = socket.request;
const {
headers: { referer },
} = req;
const roomId = referer
.split("/")
[referer.split("/").length - 1].replace(/\?./, "");
socket.join(roomId);
socket.to(roomId).emit("join", { // ❷
user: "system",
chat: `${req.session.color}님이 입장하셨습니다.`,
});
socket.on("disconnect", () => {
console.log("chat 네임스페이스 접속 해제");
socket.leave(roomId);
const currentRoom = socket.adapter.rooms[roomId]; // ❸
const userCount = currentRoom ? currentRoom.length : 0;
if (userCount === 0) {
// 접속사가 0명이면 방 삭제
axios
.delete("http://localhost:8005/room/${roomId}")
.then(() => {
console.log("방 제거 요청 성공");
})
.catch((error) => {
console.error(error);
});
} else {
socket.to(roomId).emit("exit", {
user: "system",
chat: `${req.session.color}님이 퇴장하셨습니다.`,
});
}
});
});
};
❶ io.use 메서드에 미들웨어를 장착할 수 있습니다. 이 부분은 모든 웹 소켓 연결 시마다 실행됩니다. 세션 미들웨어에 요청 객체(socket.request), 응답 객체(socket.request.res), next 함수를 인수로 넣으면 됩니다. 이제 socket.request 객체 안에 socket.request.session 객체가 생성됩니다.
❷ socket.to(방 아이디) 메서드로 특정 방에 데이터를 보낼 수 있습니다. 조금 전에 세션 미들웨어와 socket.IO를 연결했으므로 웹 소켓에서 세션을 사용할 수 있습니다. 방에 참여할 때 방에 누군가가 입장했다는 시스템 메시지를 보냅니다.
❸ 접속 해제 시에는 현재 방의 사람 수를 구해서 참여자 수가 0명이면 방에 제거하는 HTTP 요청을 보냅니다. socket.adapter.rooms[방 아이디]에 참여 중인 소켓 정보가 들어 있습니다. 참여자 수가 0명이 아니면 방에 남아 있는 참여자에게 퇴장했다는 데이터를 보냅니다.
'프로그래밍 언어 > NODE JS' 카테고리의 다른 글
| 채팅 구현하기 (0) | 2026.02.07 |
|---|---|
| 미들웨어와 소켓 연결하기(2) (0) | 2026.02.04 |
| 실시간 GIF 채팅방 만들기(4) (0) | 2026.01.29 |
| 실시간 GIF 채팅방 만들기(3) (0) | 2026.01.26 |
| 실시간 GIF 채팅방 만들기(2) (0) | 2026.01.23 |