Socket.IO Middleware
io.use, একাধিক middleware, error pass, namespace middleware ও rate limiting — বাংলায়।
Middleware হলো প্রতিটি connection-এর আগে চালু হওয়া function — এখানে auth, log, rate limit, session load করা হয়। Server-এর প্রতিটি socket-এ একবার connector-establish হওয়ার আগে middleware চলে।
শেখার লক্ষ্য
io.use()দিয়ে middleware লেখা- একাধিক middleware-এর ক্রম
- error দিয়ে connection প্রত্যাখ্যান
- namespace-ভিত্তিক middleware
Basic Middleware
io.use((socket, next) => {
console.log("handshake:", socket.id, socket.handshake.address);
next(); // অবশ্যই কল করতে হবে
});io.use() প্রতিটি connection-এর আগে চলে। next() না ডাকলে client আটকে থাকে।
Multiple Middleware
একাধিক middleware হলে registration order-এ চলে:
io.use((socket, next) => {
console.log("1. log");
next();
});
io.use((socket, next) => {
console.log("2. auth");
// token verify...
next();
});
io.on("connection", (socket) => {
console.log("3. connected"); // সবার শেষে
});Error Handling
next(new Error(...)) দিলে connection প্রত্যাখ্যান হয়; client connect_error পায়।
io.use((socket, next) => {
if (!socket.handshake.auth.token) {
const err = new Error("unauthorized");
err.data = { code: "AUTH_REQUIRED" }; // কাস্টম info
return next(err);
}
next();
});// client
socket.on("connect_error", (err) => {
console.log(err.message); // "unauthorized"
console.log(err.data?.code); // "AUTH_REQUIRED"
});Namespace Middleware
const admin = io.of("/admin");
// নোট: root `io.use` এখানে চলে না — এই namespace-এ আলাদা verify করতে হবে
admin.use((socket, next) => {
const token = socket.handshake.auth.token;
try {
const payload = jwt.verify(token, process.env.JWT_SECRET);
socket.data.user = { id: payload.sub, role: payload.role };
next();
} catch {
next(new Error("unauthorized"));
}
});
// দ্বিতীয় middleware — role check
admin.use((socket, next) => {
if (socket.data.user?.role === "admin") next();
else next(new Error("forbidden"));
});Socket.IO v3 থেকে main namespace-এ (io.use) register করা middleware কেবল `/` namespace-এ চলে — custom namespace-এ নয়। /chat বা /admin-এ middleware লাগলে সেখানে আলাদা করে io.of("/chat").use(...) লিখুন। বিদ্যমান সব namespace-এ একই middleware দিতে চাইলে একটি reusable function বানিয়ে প্রতিটিতে register করুন — বিস্তারিত Namespaces-এ।
Line-by-line
io.use((socket, next) => {...})— প্রতিটি new socket-এ চলেnext()— পরের middleware/connection-এ এগিয়ে দেয়next(new Error(...))— connection বাতিলsocket.data— middleware থেকে পরের handler-এ ডেটা বহন
Practical Use Cases
- Authentication — token verify (Authentication)
- Rate limiting — প্রতি IP-তে নির্দিষ্ট হারে connection
- Logging / analytics — কে, কোথা থেকে join করল
- Rate limit per event — হাতে counters
// সহজ rate limit
const hits = new Map();
io.use((socket, next) => {
const ip = socket.handshake.address;
const now = Date.now();
const entry = hits.get(ip) || { count: 0, start: now };
if (Date.now() - entry.start > 60_000) {
entry.count = 0;
entry.start = Date.now();
}
entry.count++;
if (entry.count > 20) return next(new Error("too many connections"));
hits.set(ip, entry);
next();
});এই in-memory middleware প্রতিটি process-এ আলাদা counter রাখে। একাধিক node চালালে Redis-এ rate limit রাখুন। বিস্তারিত Best Practices।
সাধারণ ভুল ও সমাধান
next()ভুলে যাওয়া — client চিরকাল waiting-এ; প্রতিটি path-এ next কল করুন- Exception middleware-এ — try/catch দিয়ে
next(err)করুন, নাহলে crash - ভারী কাজ — middleware দীর্ঘ sync কাজ করলে connection দেরি করে; async হলে database lookup ছোট রাখুন
Practice Task
- একটি logging middleware লিখুন — connection count log করুন
- auth middleware-এ token না থাকলে
next(new Error(...))দিন ও client-এconnect_errorদেখুন /adminnamespace-এ role middleware ব্যবহার করুন
সম্পর্কিত অধ্যায়: Authentication and Authorization · Namespaces