Custom Middleware — yaratish, next(), xatolarni uzatish
O'z middleware ingizni yozish
Tayyor middleware lar ko'p narsani hal qiladi. Lekin loyihaga xos mantiq — o'zingiz yozasiz. Masalan: foydalanuvchi rolini tekshirish, so'rov tezligini o'lchash, maxsus log format.
Middleware — uch argument oluvchi oddiy funksiya:
function myMiddleware(req, res, next) {
// 1. req ni o'qish yoki o'zgartirish
// 2. res ga yozish (va to'xtatish)
// 3. next() chaqirish (davom etish)
}
Amaliy misol — request timer
Har bir so'rov qancha vaqt olganini o'lchash:
function requestTimer(req, res, next) {
const start = Date.now();
// res.json original funksiyasini "o'rab olish":
const originalJson = res.json.bind(res);
res.json = function(data) {
const duration = Date.now() - start;
console.log(`${req.method} ${req.url} — ${duration}ms`);
return originalJson(data);
};
next();
}
app.use(requestTimer);
Amaliy misol — autentifikatsiya middleware
const jwt = require('jsonwebtoken');
function authenticate(req, res, next) {
const authHeader = req.headers['authorization'];
// Header bor-yo'qligini tekshirish
if (!authHeader) {
return res.status(401).json({ message: 'Token kerak' });
}
// Format: "Bearer <token>"
const token = authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({ message: 'Token formati noto\'g\'ri' });
}
// Tokenni tekshirish
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded; // keyingi handler lar uchun
next();
} catch (err) {
return res.status(401).json({ message: 'Token yaroqsiz' });
}
}
// Ishlatish:
app.get('/profile', authenticate, (req, res) => {
res.json(req.user);
});
Amaliy misol — rol tekshirish
Autentifikatsiya va avtorizatsiya — ikki farqli narsa. Autentifikatsiya: "sen kimsiz?" Avtorizatsiya: "senga ruxsat bormi?"
function requireRole(...roles) {
return function(req, res, next) {
if (!req.user) {
return res.status(401).json({ message: 'Login kerak' });
}
if (!roles.includes(req.user.role)) {
return res.status(403).json({ message: 'Ruxsat yo\'q' });
}
next();
};
}
// Ishlatish:
app.delete('/users/:id',
authenticate, // avval kim ekanini aniqlash
requireRole('admin', 'moderator'), // keyin ruxsatni tekshirish
(req, res) => {
res.json({ message: 'O\'chirildi' });
}
);
requireRole — middleware factory: funksiya qaytaruvchi funksiya. Bu pattern middleware ni moslashuvchan qiladi.
next(err) — xatoni uzatish
Middleware da xato chiqsa — next(err) bilan xato middleware ga uzatiladi:
function authenticate(req, res, next) {
try {
const token = req.headers['authorization']?.split(' ')[1];
req.user = jwt.verify(token, process.env.JWT_SECRET);
next();
} catch (err) {
next(err); // xato middleware ga uzatish
}
}
next() — davom etish. next(err) — xato bilan to'xtatish, error middleware ga o'tish.
Asinxron middleware
Asinxron operatsiyalar (ma'lumotlar bazasi, API) bilan ishlashda async/await ishlatiladi. Lekin xatolarni ushlamaslik — server crash bo'ladi:
// Xato — xato ushlanmaydi:
app.use(async (req, res, next) => {
const user = await db.findUser(req.userId); // xato chiqsa — crash
req.user = user;
next();
});
// To'g'ri — try/catch bilan:
app.use(async (req, res, next) => {
try {
const user = await db.findUser(req.userId);
req.user = user;
next();
} catch (err) {
next(err); // xato middleware ga uzatish
}
});
Har safar try/catch yozish zerikarli. Yordamchi funksiya:
function asyncHandler(fn) {
return (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
}
// Ishlatish — try/catch shart emas:
app.get('/users', asyncHandler(async (req, res) => {
const users = await db.getUsers();
res.json(users);
}));
asyncHandler xatoni avtomatik next(err) ga uzatadi.
Middleware ni alohida faylga chiqarish
Loyiha o'sganda middleware larni alohida faylga chiqarish — yaxshi amaliyot:
// middleware/auth.js
const jwt = require('jsonwebtoken');
module.exports = function authenticate(req, res, next) {
try {
const token = req.headers['authorization']?.split(' ')[1];
if (!token) return res.status(401).json({ message: 'Token kerak' });
req.user = jwt.verify(token, process.env.JWT_SECRET);
next();
} catch {
res.status(401).json({ message: 'Token yaroqsiz' });
}
};
// app.js
const authenticate = require('./middleware/auth');
app.get('/profile', authenticate, (req, res) => {
res.json(req.user);
});
Tez-tez uchraydigan xatolar
next() ni ikki marta chaqirish:
app.use((req, res, next) => {
next();
next(); // Xato! Ikki marta chaqirildi
});
next() faqat bir marta chaqiriladi.
Asinxron xatoni ushlamaslik:
app.use(async (req, res, next) => {
const data = await fetchData(); // xato chiqsa — UnhandledPromiseRejection
next();
});
// try/catch yoki asyncHandler kerak
next(err) o'rniga throw ishlatish:
// Xato — Express ushlamaydi:
app.use((req, res, next) => {
throw new Error('Xato'); // sinxron — ishlaydi
});
app.use(async (req, res, next) => {
throw new Error('Xato'); // asinxron — Express ushlamaydi!
// next(err) yoki asyncHandler kerak
});
Xulosa
Custom middleware — loyihaga xos mantiq uchun. Autentifikatsiya, avtorizatsiya, logging, so'rov o'lchash — bularning hammasi middleware sifatida yoziladi.
next() — davom etish. next(err) — xato bilan to'xtatish. Asinxron middleware da try/catch + next(err) yoki asyncHandler ishlatiladi.
Middleware factory pattern — requireRole('admin') kabi moslashuvchan middleware yaratish uchun.
Keyingi dars
11-dars: Error Middleware — 4 parametrli, 404 handler