Middleware tushunchasi
O‘rta dasturga kirish
Middleware Node.js veb-ilovalarining, ayniqsa Express.js’ning asosiy qismidir.
Bu ilovangizning marshrutlari va so‘nggi nuqtalari bo‘ylab umumiy funksiyalarni qo‘shish va qayta ishlatish usulini taqdim etadi.
O‘rta dasturning asosiy xususiyatlari:
- So‘rov-javob siklida bajariladi
- So‘rov va javob obyektlarini o‘zgartirishi mumkin
- So‘rov-javob siklini tugatishi mumkin
- Stekdagi keyingi o‘rta dasturni chaqirishi mumkin
- Ilova darajasida, marshrutizator darajasida yoki marshrutga xos bo‘lishi mumkin
U xom so‘rov va yakuniy mo‘ljallangan marshrut ishlovchisi o‘rtasida ko‘prik vazifasini bajaradi.
Asosan, o‘rta dastur quyidagilarga kirish huquqiga ega bo‘lgan funksiyadir:
- So‘rov obyekti (req)
- Javob obyekti (res)
- Ilovaning so‘rov-javob siklidagi keyingi o‘rta dastur funksiyasi
O‘rta dastur funksiyalari turli vazifalarni bajarishi mumkin:
- Har qanday kodni bajarish
- So‘rov va javob obyektlarini o‘zgartirish
- So‘rov-javob siklini tugatish
- Stekdagi keyingi o‘rta dastur funksiyasini chaqirish
O‘rta dasturni so‘rovlar javob olishdan oldin o‘tadigan ishlov berish qatlamlari ketma-ketligi sifatida tasavvur qiling — xuddi HTTP so‘rovlari uchun konveyer liniyasi kabi.
O‘rta dastur so‘rov-javob siklida qanday ishlaydi
O‘rta dasturiy ta’minot funksiyalari belgilangan tartibda bajariladi va so‘rovlar ketma-ket o‘tadigan zanjirni (pipeline) hosil qiladi.
Har bir middleware dastur funksiyasi so‘rov va javob obyektlari ustida operatsiyalarni bajarishi va boshqaruvni keyingi o‘rta dasturga o‘tkazish yoki so‘rov-javob siklini tugatish to‘g‘risida qaror qabul qilishi mumkin.
Middleware orqali so‘rovning lifecycle’i (hayotiy sikli):
- So‘rov server tomonidan qabul qilinadi
- Har bir o‘rta dasturdan ketma-ket o‘tadi
- Marshrut ishlovchisi so‘rovni qayta ishlaydi
- Javob middleware’lar orqali (teskari tartibda) qaytadi
- Javob mijozga yuboriladi
Express.js-dagi o‘rta dasturning asosiy namunasi ushbu tuzilishga amal qiladi:
app.use((req, res, next) => {
// Middleware code goes here
console.log('Time:', Date.now());
// Call next() to pass control to the next middleware function
next();
});
next() ni chaqirganingizda, stekdagi keyingi o‘rta dastur bajariladi.
Agar siz next() ni chaqirmasangiz, so‘rov-javob sikli tugaydi va boshqa o‘rta dastur ishlamaydi.
Misol: O‘rta dasturning oddiy zanjiri
const express = require('express');
const app = express();
// First middleware
app.use((req, res, next) => {
console.log('Middleware 1: This always runs');
next();
});
// Second middleware
app.use((req, res, next) => {
console.log('Middleware 2: This also always runs');
next();
});
// Route handler
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(8080, () => {
console.log('Server running on port 8080');
});
Misolni ishga tushirish »
Ildiz yo‘liga ('/') so‘rov yuborilganda, quyidagilar sodir bo‘ladi:
- Middleware 1 xabarni log qiladi va next()’ni chaqiradi
- Middleware 2 xabarni log qiladi va next()’ni chaqiradi
- Marshrut ishlovchisi "Hello World!" bilan javob beradi
O‘rta dastur turlari bo‘yicha keng qamrovli qo‘llanma
O‘rta dasturning har xil turlarini tushunish ilovangiz mantig‘ini samarali tashkil etishga yordam beradi.
O‘rta dasturiy ta’minotni uning ko‘lami, maqsadi va ilovaga qanday o‘rnatilganligiga qarab tasniflash mumkin.
To‘g‘ri turni tanlash: Siz foydalanadigan middleware dastur turi sizning maxsus ehtiyojlaringizga bog‘liq bo‘ladi, masalan, o‘rta dastur barcha so‘rovlar yoki muayyan marshrutlar uchun ishlashi kerakmi yoki router nusxasiga (instance) murojaat qilishi kerakmi.
Node.js ilovalarida, ayniqsa Express.js bilan, o‘rta dasturning bir nechta turlari mavjud:
Ilova darajasidagi o‘rta dastur
Ilova darajasidagi o‘rta dastur app.use() yoki app.METHOD() funksiyalaridan foydalangan holda Express ilovasi nusxasiga (instance) bog‘lanadi.
Foydalanish holatlari: Har bir so‘rov uchun bajarilishi kerak bo‘lgan loglash, autentifikatsiya, so‘rovlarni tahlil qilish va boshqa operatsiyalar.
Eng yaxshi amaliyotlar: Marshrutlarni belgilashdan oldin ularning to‘g‘ri tartibda ishlashiga ishonch hosil qilish uchun ilova darajasidagi o‘rta dasturni aniqlang.
app.use() yoki app.METHOD() yordamida ilova nusxasiga bog‘lanadi:
const express = require('express');
const app = express();
// Application-level middleware
app.use((req, res, next) => {
console.log('Time:', Date.now());
next();
});
Router darajasidagi o‘rta dastur
Router darajasidagi o‘rta dastur ilova darajasidagi o‘rta dasturga o‘xshab ishlaydi, lekin express.Router() nusxasiga bog‘lanadi.
Foydalanish holatlari: Marshrutga xos middleware dasturlarni guruhlash, API versiyalarini yaratish va marshrutlarni mantiqiy guruhlarga ajratish.
Afzalliklari: Kodni yaxshiroq tashkil etish, modulli marshrutlash va ma’lum marshrut guruhlariga o‘rta dasturni qo‘llash qobiliyati.
express.Router() nusxasiga bog‘lanadi:
const express = require('express');
const router = express.Router();
// Router-level middleware
router.use((req, res, next) => {
console.log('Router specific middleware');
next();
});
router.get('/user/:id', (req, res) => {
res.send('User profile');
});
// Add the router to the app
app.use('/api', router);
Xatolarni boshqarish o‘rta dasturiy ta’minoti
Xatolarni qayta ishlovchi o‘rta dastur to‘rtta argument (err, req, res, next) bilan aniqlanadi va so‘rovni qayta ishlash jarayonida yuzaga keladigan xatolarni qayta ishlash uchun ishlatiladi.
Asosiy fikrlar:
- Aynan to‘rtta parametrga ega bo‘lishi shart
- Boshqa
app.use()va marshrut chaqiruvlaridan keyin aniqlanishi kerak - Xatolarni boshqarish mantiqini markazlashtirish uchun foydalanish mumkin
next(err)yordamida xatolarni keyingi xato ishlov beruvchiga yuborishi mumkin
Uchta o‘rniga to‘rtta argument bilan aniqlanadi (err, req, res, next):
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
O‘rnatilgan o‘rta dastur
Express umumiy veb-ilova vazifalarini bajaradigan bir nechta o‘rnatilgan o‘rta dastur funksiyalarini o‘z ichiga oladi.
Umumiy o‘rnatilgan o‘rta dastur:
express.json(): JSON formatidagi so‘rov body’larini tahlil qilishexpress.urlencoded(): URL-kodlangan so‘rov body’larini tahlil qilishexpress.static(): Statik fayllarni uzatish (serve)express.Router(): Modulli marshrut ishlovchilarini yaratish
Eng yaxshi amaliyot: Iloji bo‘lsa, har doim o‘rnatilgan o‘rta dasturdan foydalaning, chunki ular Express jamoasi tomonidan yaxshi sinovdan o‘tgan va doimiy qo‘llab-quvvatlanadi.
Express ba’zi o‘rnatilgan o‘rta dastur funksiyalari bilan birga keladi:
// Parse JSON bodies
app.use(express.json());
// Parse URL-encoded bodies
app.use(express.urlencoded({ extended: true }));
// Serve static files
app.use(express.static('public'));
Uchinchi tomon o‘rta dasturiy ta’minoti
Node.js ekotizimi Express funksiyalarini kengaytiruvchi ko‘plab uchinchi tomon o‘rta dasturlar paketlarini taklif etadi.
Mashhur uchinchi tomon o‘rta dasturlari:
- Helmet: Turli HTTP sarlavhalarini belgilash orqali ilovangizni himoyalang
- Morgan: HTTP so‘rovlarini qayd qiluvchi
- CORS: CORS-ni turli xil variantlar bilan yoqing
- Compression: HTTP javoblarini siqish
- Cookie-parser: Cookie sarlavhasini tahlil qiling va
req.cookies’ni to‘ldiring
O‘rnatish misoli: npm install helmet morgan cors compression cookie-parser
Express ilovalariga funksionallik qo‘shadigan tashqi o‘rta dastur:
const morgan = require('morgan');
const helmet = require('helmet');
// HTTP request logger
app.use(morgan('dev'));
// Security headers
app.use(helmet());
Keng tarqalgan uchinchi tomon o‘rta dasturlari:
morgan(loglash)helmet(xavfsizlik)cors(cross-origin resource sharing — domenlararo resurs almashish)compression(javoblarni siqish)cookie-parser(cookie’lar bilan ishlash)
Maxsus o‘rta dasturni yaratish va ishlatish
Maxsus o‘rta dasturiy ta’minotni yaratish ilovaga xos funksiyalarni qayta foydalanish mumkin bo‘lgan tarzda amalga oshirish imkonini beradi.
Yaxshi ishlab chiqilgan o‘rta dastur bitta vazifaga qaratilgan, test qilish oson va yagona mas’uliyat tamoyiliga amal qiladigan bo‘lishi kerak.
Maxsus o‘rta dastur uchun eng yaxshi amaliyotlar:
- O‘rta dasturni bitta mas’uliyatga qarating
- O‘rta dasturning maqsadi va talablarini hujjatlashtiring
- Xatolarni to‘g‘ri qayta ishlang
- Unumdorlikka ta’sirini hisobga oling
- O‘rta dasturni parametrlar (options) orqali sozlanadigan qiling
O‘zingizning o‘rta dasturiy ta’minot funksiyalaringizni yaratish juda oddiy va ilovangizga maxsus funksiyalarni qo‘shish imkonini beradi.
Misol: Oddiy logger o‘rta dasturi
// Create a simple logging middleware
function requestLogger(req, res, next) {
const timestamp = new Date().toISOString();
console.log(`${timestamp} - ${req.method} ${req.url}`);
next(); // Don't forget to call next()
}
// Use the middleware
app.use(requestLogger);
Misol: Autentifikatsiya o‘rta dasturi
// Authentication middleware
function authenticate(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader) {
return res.status(401).send('Authentication required');
}
const token = authHeader.split(' ')[1];
// Verify the token (simplified)
if (token === 'secret-token') {
// Authentication successful
req.user = { id: 123, username: 'john' };
next();
} else {
res.status(403).send('Invalid token');
}
}
// Apply to specific routes
app.get('/api/protected', authenticate, (req, res) => {
res.json({ message: 'Protected data', user: req.user });
});
Misolni ishga tushirish »
Misol: So‘rovni validatsiya qiluvchi o‘rta dastur
// Validate a user creation request
function validateUserCreation(req, res, next) {
const { username, email, password } = req.body;
// Simple validation
if (!username || username.length < 3) {
return res.status(400).json({ error: 'Username must be at least 3 characters' });
}
if (!email || !email.includes('@')) {
return res.status(400).json({ error: 'Valid email is required' });
}
if (!password || password.length < 6) {
return res.status(400).json({ error: 'Password must be at least 6 characters' });
}
// Validation passed
next();
}
// Apply to user creation route
app.post('/api/users', validateUserCreation, (req, res) => {
// Process valid user creation
res.status(201).json({ message: 'User created successfully' });
});
Xatolarni boshqarish o‘rta dasturiy ta’minoti
Xatolarni qayta ishlovchi o‘rta dastur o‘ziga xos, chunki u uchta o‘rniga to‘rtta parametr qabul qiladi: (err, req, res, next).
Misol: Asosiy xato ishlov beruvchisi
const express = require('express');
const app = express();
// Regular route that might throw an error
app.get('/error-demo', (req, res, next) => {
try {
// Simulate an error
throw new Error('Something went wrong!');
} catch (error) {
next(error); // Pass error to the error handler
}
});
// Error-handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
message: 'An error occurred',
error: process.env.NODE_ENV === 'production' ? {} : err
});
});
Misolni ishga tushirish »
Asinxron xatolar bilan ishlash
Asinxron o‘rta dasturda Promise rad etilishlarini (rejection) ushlab, ularni next() ga uzating:
// Async middleware with proper error handling
app.get('/async-data', async (req, res, next) => {
try {
const data = await fetchDataFromDatabase();
res.json(data);
} catch (error) {
next(error); // Pass error to the error handler
}
});
// Alternative using Express 4.16+ wrapper
function asyncHandler(fn) {
return (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
}
app.get('/better-async', asyncHandler(async (req, res) => {
const data = await fetchDataFromDatabase();
res.json(data);
}));
Eslatma: Express 5 (hozirda beta-versiyada) Promise rad etilishlarini avtomatik ushlaydi va ularni xato ishlovchisiga (error handler) uzatadi.
O‘rta dasturni bajarish tartibi
O‘rta dasturni belgilash tartibi muhim ahamiyatga ega.
Express o‘rta dasturlarni ilovaga qo‘shilgan tartibda bajaradi.
Misol: Tartib muhim
const express = require('express');
const app = express();
// This middleware will run first
app.use((req, res, next) => {
console.log('First middleware');
next();
});
// This middleware will run for /users paths only
app.use('/users', (req, res, next) => {
console.log('Users middleware');
next();
});
// This route handler will run when matched
app.get('/users', (req, res) => {
res.send('Users list');
});
// This middleware will never run for successfully matched routes
// because route handlers end the request-response cycle
app.use((req, res, next) => {
console.log('This will not run for matched routes');
next();
});
// This is a "catch-all" middleware for unmatched routes
app.use((req, res) => {
res.status(404).send('Not found');
});
Misolni ishga tushirish »
Middleware tartibi bo‘yicha eng yaxshi amaliyotlar:
- Barcha so‘rovlarga taalluqli middleware’larni birinchi o‘ringa qo‘ying (loglash, xavfsizlik, body’ni tahlil qilish)
- Keyinchalik aniqroq o‘rta dastur va marshrutlarni joylashtiring
- Xatolarni qayta ishlash uchun o‘rta dasturni oxirgi joylashtiring
Misol: Tavsiya etilgan tartib
// 1. Application-wide middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(morgan('dev'));
app.use(helmet());
// 2. Route-specific middleware
app.use('/api', authenticate);
// 3. Routes
app.use('/api/users', userRoutes);
app.use('/api/products', productRoutes);
// 4. 404 handler
app.use((req, res) => {
res.status(404).json({ message: 'Not found' });
});
// 5. Error handler (always last)
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({ message: 'Server error' });
});
Eng yaxshi amaliyotlar
Node.js da o‘rta dastur bilan ishlashda quyidagi eng yaxshi amaliyotlarga amal qiling:
1. O‘rta dasturni bitta vazifaga qarating
Har bir o‘rta dastur Yagona javobgarlik printsipiga rioya qilgan holda yagona javobgarlikka ega bo‘lishi kerak.
2. Next()’dan to‘g‘ri foydalaning
- Agar javobni yakunlamayotgan bo‘lsangiz, har doim
next()ni chaqiring - Javob yuborganingizdan keyin hech qachon
next()ni chaqirmang - Xatolarni qayta ishlashni boshlash uchun xato parametri bilan
next()ni chaqiring
3. Asinxron kodni to‘g‘ri qayta ishlang
Asinxron o‘rta dasturdagi xatolarni har doim ushlang va ularni next() ga uzating.
4. O‘rta dasturni ortiqcha ishlatmang
Juda ko‘p o‘rta dastur funksiyalari unumdorlikka ta’sir qilishi mumkin. Ulardan oqilona foydalaning.
5. Domen bo‘yicha tashkil qilish
Bir-biriga bog‘liq o‘rta dasturlarni funksionallik bo‘yicha alohida fayllarga guruhlang.
// middleware/auth.js
exports.authenticate = (req, res, next) => {
// Authentication logic
};
exports.requireAdmin = (req, res, next) => {
// Admin verification logic
};
// In your app.js
const { authenticate, requireAdmin } = require('./middleware/auth');
app.use('/admin', authenticate, requireAdmin);
6. Shartli Next()’dan foydalaning
O‘rta dastur shartlarga asoslanib zanjirni davom ettirish to‘g‘risida qaror qabul qilishi mumkin:
// Rate limiting middleware example
function rateLimit(req, res, next) {
const ip = req.ip;
// Check if IP has made too many requests
if (tooManyRequests(ip)) {
return res.status(429).send('Too many requests');
// Note: we don't call next() here
}
// Otherwise continue
next();
}
Professional maslahat: Muayyan sozlamalarga ega o‘rta dasturni hosil qiluvchi funksiyalarni qaytarish orqali qayta ishlatiladigan o‘rta dastur fabrikalarini (middleware factory) yarating.
// Middleware factory
function requireRole(role) {
return (req, res, next) => {
if (req.user && req.user.role === role) {
next();
} else {
res.status(403).send('Access denied');
}
};
}
// Usage
app.get('/admin', authenticate, requireRole('admin'), (req, res) => {
res.send('Admin dashboard');
});
app.get('/editor', authenticate, requireRole('editor'), (req, res) => {
res.send('Editor dashboard');
});
W3Schools Pathfinder
Yutuqlaringizni kuzating – bu bepul!
