5.10-bob: Error handling middleware, global error handler
5-QISM — Node.js Backend · 10-mavzu
1. Kirish va motivatsiya
2.12-bobda JavaScript'da xatolarni (try/catch, custom error class) o'rgandik. 5.6-bobda Express error middleware'ni (4 argument), 5.9-bobda validatsiya xatolarini ko'rdik. Endi hammasini birlashtirib, butun ilovadagi xatolarni bir joyda, izchil, professional boshqarishni — global error handlerni — chuqur o'rganamiz.
Xato handling — havaskor va professional backend'ni eng aniq ajratadigan narsa. Yangi dasturchi har route'da try/catch yozadi, xato xabarlarini har xil qaytaradi, ba'zida xatoni umuman e'tiborsiz qoldiradi (server qulaydi). Professional — markazlashtirilgan error handling quradi: har route xatoni faqat tashlaydi (throw), bitta global handler uni ushlab, izchil javob qaytaradi, log qiladi, va serverni qulashdan saqlaydi.
O'xshatish: error handling — binoning yong'in xavfsizligi tizimi. Har xonada alohida o'choq emas (har route'da try/catch) — balki markaziy tizim: har joydagi tutun (xato) datchikka (next(err)) boradi, markaziy panel (global handler) javob beradi (signal, suv), hodisani qayd qiladi (log). Markazlashgan, izchil, ishonchli.
Nega muhim?
- Barqarorlik — xato serverni qulatmaydi (boshqa foydalanuvchilar ishlaydi).
- Izchillik — har xato bir xil formatda 5.7-bob — frontend 11.10-bob bashorat qiladi.
- Xavfsizlik (14) — texnik tafsilot (DB struktura, stack) foydalanuvchiga oshkor qilinmaydi.
- Debug/monitoring — xatolar bir joyda log qilinadi (5.12: Winston, Sentry — 10.9).
2. Nazariya — chuqur tushuntirish
2.1. Markazlashtirilgan error handling falsafasi
Asosiy g'oya: route'lar xatoni hal qilmaydi, balki tashlaydi (throw yoki next(err)); bitta global handler hammasini ushlaydi (expressjs.com):
Har route'da: Markazlashgan:
try { ... } catch (e) { route: throw new AppError(...)
res.status(500).json(...) │ next(err)
} ▼
(har joyda takror, har xil) [GLOBAL ERROR HANDLER]
(bir joyda: log + izchil javob)Foyda: route'lar toza (faqat biznes logika); xato javobi bir joyda (izchil — 5.7); o'zgartirish oson (bir joyni).
2.2. Operational vs Programmer xatolar (muhim farq)
Xatolar ikki turga bo'linadi (Toptal, best practices):
- Operational (kutilgan) xatolar — ilovaning normal qismi: noto'g'ri kirish 5.9-bob, topilmadi (404), ruxsat yo'q (401/403), tarmoq uzilishi. Bularni boshqaramiz (foydalanuvchiga aniq javob).
- Programmer (bug) xatolar — kutilmagan kod xatolari:
undefinedga murojaat (2.1-JS), typo, noto'g'ri mantiq. Bular — bug; ularni tuzatish kerak, "boshqarib" yashirmaslik.
Operational: "Email band" (409), "Topilmadi" (404) foydalanuvchiga javob
Programmer: "Cannot read properties of undefined" log + (kerak bo'lsa) crash + restartNega farq muhim: operational xatoda — foydalanuvchiga chiroyli javob (4xx). Programmer xatoda — bu bug; uni yashirmasdan log qiling, kuzating (5.12, 10.9), tuzating. Jiddiy bug'da — graceful crash + restart (PM2 — 10.7), chunki ilova "noto'g'ri holatda" bo'lishi mumkin 2.10-bob.
2.3. Custom error class iyerarxiyasi (2.12-JS chuqur)
Markazlashgan handling uchun custom error class (2.12-JS, 2.10-JS: extends) — xatoga status, kod, operational flag biriktiradi:
// Asosiy operational error
class AppError extends Error {
constructor(message, statusCode = 500) {
super(message);
this.statusCode = statusCode; // HTTP status (5.7)
this.isOperational = true; // kutilgan xato 2.2-bob — bug emas
Error.captureStackTrace(this, this.constructor); // toza stack (5.12)
}
}
// Maxsus xatolar (2.10-JS: inheritance)
class NotFoundError extends AppError {
constructor(resurs = "Resurs") { super(`${resurs} topilmadi`, 404); }
}
class ValidationError extends AppError {
constructor(message, details) { super(message, 400); this.details = details; }
}
class UnauthorizedError extends AppError {
constructor() { super("Avtorizatsiya kerak", 401); } // (5.7: 401)
}
class ForbiddenError extends AppError {
constructor() { super("Ruxsat yo'q", 403); } // (5.7: 403)
}
isOperationalflag — handler'ga "bu kutilgan xatomi (foydalanuvchiga javob) yoki bug (log + ehtiyot)?" deyishga yordam beradi 2.2-bob.
2.4. Global error handler middleware (4 argument!)
Global handler — 4 argumentli middleware (5.6: shuning uchun Express uni error handler deb biladi), eng oxirda (expressjs.com):
const errorHandler = (err, req, res, next) => { // 4 ARGUMENT (5.6)
// Default qiymatlar
const statusCode = err.statusCode || 500; // (2.3)
const isOperational = err.isOperational || false;
// Log 5.12-bob — programmer xato bo'lsa to'liq
if (!isOperational) console.error("BUG:", err.stack);
// Izchil javob 5.7-bob — prod'da texnik tafsilot YASHIRIN (14)
res.status(statusCode).json({
success: false,
error: {
message: isOperational ? err.message : "Ichki server xatosi", // bug'da yashir (14)
...(err.details && { details: err.details }), // validatsiya (5.9)
...(process.env.NODE_ENV !== "production" && { stack: err.stack }),// dev'da stack (5.8)
},
});
};
// ENG OXIRDA (barcha route'lardan keyin — 5.6)
app.use(errorHandler);2.5. next(err) — xatoni handler'ga uzatish
Route'da xato bo'lsa, uni next(err) bilan global handler'ga uzatish (5.6, expressjs.com):
app.get("/users/:id", (req, res, next) => {
const user = users.find(u => u.id === Number(req.params.id));
if (!user) {
return next(new NotFoundError("Foydalanuvchi")); // handler'ga uzat (2.4)
}
res.json(user);
});
throwvsnext(err): sinxron koddathrowham ishlaydi (Express ushlaydi). Asinxron (2.11-JS) kodda —next(err)(yoki Express 5 / wrapper — 2.6). Ikkalasi ham global handler'ga boradi.
2.6. Async xato handling (eng muhim nuans)
Express 4 async (2.11-JS) xatolarni avtomatik ushlamaydi (5.6: shuni ko'rgandik). Async handler'da throw qilsangiz — Express bilmaydi, so'rov "osiladi" yoki process qulaydi:
// async xato ushlanmaydi (Express 4)
app.get("/x", async (req, res) => {
const data = await DB.query(); // xato ushlanmaydi!
res.json(data);
});
// Yechim 1: try/catch + next(err)
app.get("/x", async (req, res, next) => {
try {
res.json(await DB.query());
} catch (err) {
next(err); // handler'ga (2.5)
}
});
// Yechim 2: async wrapper (DRY — eng yaxshi)
const catchAsync = (fn) => (req, res, next) => fn(req, res, next).catch(next);
app.get("/x", catchAsync(async (req, res) => {
res.json(await DB.query()); // xato avtomatik next(err)ga
}));
// Yechim 3: express-async-errors paketi (import qilsa, avtomatik)
// import "express-async-errors";
// Express 5: avtomatik (next(err) shart emas — best practices)Tavsiya: async wrapper (
catchAsync) — eng keng tarqalgan, toza yechim (Express 4'da). Yokiexpress-async-errorspaketi. Express 5'da — avtomatik (kelajak). NestJS 8.6-bob buni butunlay hal qiladi.
2.7. 404 handler (route topilmadi)
Hech bir route mos kelmasa — 404 (5.5, 5.6). Buni route'lardan keyin, error handler'dan oldin middleware bilan:
// Barcha route'lardan KEYIN
app.use((req, res, next) => {
next(new NotFoundError(`Yo'l: ${req.originalUrl}`)); // handler'ga (2.4, 2.5)
});
// keyin error handler (2.4)
app.use(errorHandler);2.8. Error handler tartibi (joylashuv muhim)
Error handler majburiy oxirda (5.6: tartib):
app.use(express.json()) 1. middleware'lar
app.use("/api", routes) 2. route'lar
app.use(404 handler) 3. 404 (route topilmadi)
app.use(errorHandler) 4. ERROR HANDLER (eng oxirgi!)Agar error handler route'lardan oldin bo'lsa — u hech qachon ishlamaydi (so'rov route'ga yetmaydi). Doim oxirda.
2.9. Bir nechta error handler
Murakkab ilovada bir nechta error handler bo'lishi mumkin (har biri next(err) bilan keyingisiga uzatadi — 5.6):
// 1. Maxsus xatolar (DB, validatsiya)
app.use((err, req, res, next) => {
if (err.name === "ZodError") return res.status(400).json({...}); // (5.9)
if (err.code === "11000") return res.status(409).json({...}); // MongoDB duplicate (6)
next(err); // boshqasini keyingiga uzat
});
// 2. Umumiy fallback handler
app.use(errorHandler);2.10. Texnik tafsilotni yashirish (xavfsizlik — 14)
Production'da xato javobida texnik tafsilot (stack, DB xato, fayl yo'li) oshkor qilinmaydi (14): hacker'ga ma'lumot beradi:
Production'da: { error: "ECONNREFUSED 127.0.0.1:5432 ...", stack: "..." }
(DB manzili, kod tuzilishi oshkor — 14)
Production'da: { error: "Ichki server xatosi" } (umumiy)
Dev'da: + stack (debug uchun — 5.8: NODE_ENV)
Har holatda: to'liq xato LOG'da 5.12-bob — kuzatish uchun2.11. Xatolarni log qilish (5.12 ga ko'prik)
Global handler — xatolarni markaziy log qilish joyi (best practices). console.error — boshlash uchun; production'da Winston/Pino 5.12-bob, va Sentry 10.9-bob kabi monitoring:
const errorHandler = (err, req, res, next) => {
logger.error({ // Winston (5.12)
message: err.message,
stack: err.stack,
url: req.originalUrl, // qaysi so'rov
method: req.method,
user: req.user?.id, // kim (5.15)
});
// ... javob ...
};2.12. Process-level xatolar (uncaughtException, unhandledRejection)
Express handler faqat so'rov ichidagi xatolarni ushlaydi. So'rovdan tashqari (yoki ushlanmagan async — 2.11-JS) xatolar — process darajasida (5.1: process):
// Ushlanmagan Promise rad etilishi (2.11-JS)
process.on("unhandledRejection", (reason) => {
logger.error("Unhandled Rejection:", reason); // log (5.12)
// graceful shutdown (2.13)
});
// Ushlanmagan sinxron xato (programmer error — 2.2)
process.on("uncaughtException", (err) => {
logger.error("Uncaught Exception:", err);
process.exit(1); // CRASH (bug — holat ishonchsiz, 2.2)
// PM2 10.7-bob qayta ishga tushiradi
});
uncaughtException'dan keyin process'ni to'xtating (process.exit(1)) — bu programmer error (bug — 2.2); ilova "noto'g'ri holatda" bo'lishi mumkin. Log qilib, graceful crash + restart (PM2 — 10.7) eng xavfsiz (best practices). Davom etish — yashirin buzilishlarga olib keladi.
2.13. Graceful shutdown (xato/signal'da)
Server o'chayotganda (deploy — 10, fatal xato) — yangi so'rovni qabul qilmay, joriy so'rovlarni tugatib yopilish (5.5: graceful shutdown):
const server = app.listen(3000);
process.on("SIGTERM", () => { // (5.5, 0.3: signal)
logger.info("SIGTERM: server yopilmoqda");
server.close(() => { // joriy so'rovlarni tugatib yop
// DB ulanishlarni yop (6), Redis 5.21-bob...
process.exit(0);
});
});2.14. Validatsiya va DB xatolarini moslash (5.9, 6)
Tashqi kutubxona xatolarini (Zod, Mongoose) o'z formatingga moslash — error handler'da yoki maxsus handler'da 2.9-bob:
const errorHandler = (err, req, res, next) => {
// Zod validatsiya xatosi (5.9)
if (err.name === "ZodError") {
return res.status(400).json({ success: false, error: { code: "VALIDATION", details: err.flatten().fieldErrors } });
}
// Mongoose noto'g'ri ID (6)
if (err.name === "CastError") {
return res.status(400).json({ success: false, error: { message: "Noto'g'ri ID" } });
}
// MongoDB duplicate key (6)
if (err.code === 11000) {
return res.status(409).json({ success: false, error: { message: "Allaqachon mavjud" } }); // (5.7: 409)
}
// ... umumiy ...
};2.15. To'liq error handling arxitekturasi (xulosa)
Route handler (catchAsync bilan — 2.6)
│ throw new NotFoundError(...) yoki next(err)
▼
[Maxsus error handler'lar] (Zod/Mongoose moslash — 2.14)
│ next(err)
▼
[Global error handler] (izchil javob + log — 2.4, 2.11)
│
▼
Javob 5.7-bob — operational: aniq; programmer: umumiy (14)
Tashqari (process — 2.12): uncaughtException/unhandledRejection log + crash PM2 restart3. Sintaksis — tez ma'lumotnoma
// Custom error (2.3)
class AppError extends Error {
constructor(msg, status) { super(msg); this.statusCode = status; this.isOperational = true; }
}
// Async wrapper (2.6)
const catchAsync = (fn) => (req, res, next) => fn(req, res, next).catch(next);
// Route — throw/next (2.5)
if (!user) throw new NotFoundError(); // yoki next(new ...)
// Tartib (2.8)
app.use(routes);
app.use(notFoundHandler); // 404
app.use(errorHandler); // 4 argument, ENG OXIRDA
// Process (2.12)
process.on("unhandledRejection", ...); process.on("uncaughtException", ...);4. Batafsil kod namunalari
Misol 1 — Custom error class iyerarxiyasi (2.3)
// errors/AppError.js
export class AppError extends Error {
constructor(message, statusCode = 500) {
super(message);
this.statusCode = statusCode;
this.isOperational = true; // kutilgan (2.2)
this.name = this.constructor.name;
Error.captureStackTrace(this, this.constructor);
}
}
export class NotFoundError extends AppError {
constructor(resurs = "Resurs") { super(`${resurs} topilmadi`, 404); }
}
export class BadRequestError extends AppError {
constructor(message = "Noto'g'ri so'rov") { super(message, 400); }
}
export class UnauthorizedError extends AppError {
constructor(message = "Avtorizatsiya kerak") { super(message, 401); }
}
export class ForbiddenError extends AppError {
constructor(message = "Ruxsat yo'q") { super(message, 403); }
}
export class ConflictError extends AppError {
constructor(message = "Ziddiyat") { super(message, 409); }
}Misol 2 — Async wrapper (2.6)
// utils/catchAsync.js — try/catch takrorlanishini tugatadi (DRY)
export const catchAsync = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next); // xato next(err) (2.5)
};Misol 3 — Global error handler (2.4, 2.10, 2.14)
// middleware/errorHandler.js
import { config } from "../config/index.js"; // (5.8)
import { logger } from "../utils/logger.js"; // (5.12)
export const errorHandler = (err, req, res, next) => {
let statusCode = err.statusCode || 500;
let message = err.message;
// Tashqi xatolarni moslash (2.14)
if (err.name === "ZodError") { // (5.9)
statusCode = 400;
return res.status(400).json({ success: false, error: { code: "VALIDATION", details: err.flatten().fieldErrors } });
}
if (err.name === "CastError") { statusCode = 400; message = "Noto'g'ri ID"; } // (6)
if (err.code === 11000) { statusCode = 409; message = "Allaqachon mavjud"; } // (6)
// Log 2.11-bob — programmer xato to'liq, operational qisqaroq
if (statusCode >= 500) {
logger.error({ message: err.message, stack: err.stack, url: req.originalUrl, method: req.method });
}
// Javob 2.10-bob — prod'da 5xx tafsilotni yashir (14)
res.status(statusCode).json({
success: false,
error: {
message: (statusCode >= 500 && config.isProd) ? "Ichki server xatosi" : message,
...(!config.isProd && { stack: err.stack }), // dev'da stack (5.8)
},
});
};Misol 4 — Route'larda ishlatish (2.5, 2.6)
import { catchAsync } from "../utils/catchAsync.js";
import { NotFoundError, ConflictError } from "../errors/AppError.js";
// Async — wrapper bilan; xato faqat THROW (try/catch yo'q — toza!)
export const getUser = catchAsync(async (req, res) => {
const user = await User.findById(req.params.id); // DB (6)
if (!user) throw new NotFoundError("Foydalanuvchi"); // global handler (2.5)
res.json({ success: true, data: user });
});
export const createUser = catchAsync(async (req, res) => {
const mavjud = await User.findOne({ email: req.body.email });
if (mavjud) throw new ConflictError("Email band"); // 409 (2.3)
const user = await User.create(req.body);
res.status(201).json({ success: true, data: user });
});
// Route'lar toza — faqat biznes logika; xato markazda boshqariladi (2.1)Misol 5 — To'liq app.js (tartib — 2.8)
import express from "express";
import userRoutes from "./routes/users.js";
import { errorHandler } from "./middleware/errorHandler.js";
import { NotFoundError } from "./errors/AppError.js";
const app = express();
app.use(express.json()); // 1. middleware (5.6)
app.use("/api/users", userRoutes); // 2. route'lar
// 3. 404 handler (route topilmadi — 2.7)
app.use((req, res, next) => {
next(new NotFoundError(`Yo'l: ${req.originalUrl}`));
});
// 4. GLOBAL ERROR HANDLER (eng oxirgi — 2.8)
app.use(errorHandler);
export default app;Misol 6 — Process-level handlerlar (2.12, 2.13)
// server.js
import app from "./app.js";
import { logger } from "./utils/logger.js"; // (5.12)
const server = app.listen(3000, () => logger.info("Server 3000-portda"));
// Ushlanmagan Promise (2.11-JS, 2.12)
process.on("unhandledRejection", (reason) => {
logger.error("UNHANDLED REJECTION:", reason);
server.close(() => process.exit(1)); // graceful 2.13-bob PM2 restart (10.7)
});
// Ushlanmagan sinxron xato — programmer bug (2.2, 2.12)
process.on("uncaughtException", (err) => {
logger.error("UNCAUGHT EXCEPTION:", err);
process.exit(1); // darrov to'xta (2.12)
});
// Graceful shutdown (deploy — 2.13)
process.on("SIGTERM", () => {
logger.info("SIGTERM qabul qilindi");
server.close(() => {
logger.info("Server yopildi");
process.exit(0);
});
});Misol 7 — Sinxron throw (Express avtomatik ushlaydi — 2.5)
// SINXRON route'da throw — Express o'zi ushlaydi (next kerak emas)
app.get("/sync", (req, res) => {
if (!req.query.id) throw new BadRequestError("id kerak"); // sinxron handler (2.5)
res.json({ id: req.query.id });
});
// LEKIN async'da — wrapper kerak 2.6-bob! Bu farqni esda tuting.Misol 8 — Operational vs programmer (2.2)
// Operational (kutilgan) — isOperational: true foydalanuvchiga javob
throw new NotFoundError("Mahsulot"); // 404, aniq javob (2.2)
// Programmer (bug) — oddiy Error handler "Ichki server xatosi" + log (14)
const x = undefined;
x.foo; // TypeError (bug) 500, log, yashir
// Handler ajratadi 2.4-bob:
// err.isOperational ? err.message : "Ichki server xatosi"5. To'g'ri va noto'g'ri holatlar
1) Har route'da try/catch + res (markazlashtirilmagan)
// takror, har xil format (2.1)
app.get("/a", async (req, res) => { try {...} catch(e){ res.status(500).json({err: e.message}) } });
// catchAsync + throw + global handler (2.6, 2.4)
app.get("/a", catchAsync(async (req, res) => { ...; throw new NotFoundError(); }));2) Async xatoni ushlamaslik
// async throw — Express 4 ushlamaydi osiladi/qulaydi (2.6)
app.get("/x", async (req, res) => { await DB.query(); });
// catchAsync wrapper
app.get("/x", catchAsync(async (req, res) => {...}));3) Texnik xatoni foydalanuvchiga oshkor qilish
// stack/DB xato javobda (production — 14, 2.10)
res.status(500).json({ error: err.stack });
// prod'da umumiy, dev'da stack (5.8)4) uncaughtException'da davom etish
// log qilib, davom etish (ilova noto'g'ri holatda — 2.2, 2.12)
process.on("uncaughtException", (e) => console.error(e)); // exit yo'q!
// log + exit + PM2 restart (2.12)
process.on("uncaughtException", (e) => { logger.error(e); process.exit(1); });5) Error handler noto'g'ri joyda (3 argument)
// route'dan oldin yoki 3 argument (ishlamaydi — 2.8, 5.6)
app.use((err, req, res) => {...}); // 3 argument!
// 4 argument, eng oxirda
app.use((err, req, res, next) => {...});6. Keng tarqalgan xatolar va yechimlari
Xato 1 — Server bitta xatodan qulaydi
Sababi: ushlanmagan xato/rejection 2.12-bob. Yechimi: global handler + catchAsync 2.6-bob + process handlerlar 2.12-bob; PM2 10.7-bob.
Xato 2 — Async route'da xato "yo'qoladi" (so'rov osiladi)
Sababi: async throw ushlanmadi 2.6-bob. Yechimi: catchAsync wrapper yoki express-async-errors.
Xato 3 — Error handler ishlamaydi
Sababi: 3 argument yoki noto'g'ri joyda (2.8, 5.6). Yechimi: 4 argument; eng oxirda.
Xato 4 — Cannot set headers after they are sent
Sababi: javob yuborilgach, yana javob (yoki nextdan keyin — 5.5). Yechimi: return next(err); bitta javob; handler'da res.headersSent tekshir.
Xato 5 — Production'da maxfiy ma'lumot oshkor
Sababi: stack/DB xato javobda (2.10, 14). Yechimi: NODE_ENV bo'yicha yashiring 5.8-bob.
Xato 6 — Validatsiya/DB xatosi 500 bo'lib chiqadi
Sababi: tashqi xato moslanmagan 2.14-bob. Yechimi: handler'da err.name/err.code bo'yicha to'g'ri status (400/409 — 2.14).
7. Integratsiya — bu mavzu stack'ning qayerida uchraydi
- JS error handling 2.12-bob: custom error class, try/catch.
- Express 5.6-bob: error middleware (4 argument), next(err).
- REST 5.7-bob: izchil xato formati, to'g'ri status.
- Validatsiya 5.9-bob: Zod xatosi 400 2.14-bob.
- DB (6): Mongoose/SQL xatolarini moslash 2.14-bob.
- Logger 5.12-bob: xatolarni log qilish (Winston/Pino).
- Monitoring 10.9-bob: Sentry — xato kuzatuvi.
- Deploy 10.7-bob: PM2 — crash'da restart.
- NestJS 8.6-bob: Exception Filters — shu g'oya, avtomatik.
8. Eng yaxshi amaliyotlar (best practices)
- Markazlashtirilgan global handler — route'lar faqat
throw/next(err)2.1-bob. - Custom error class iyerarxiyasi (statusCode, isOperational — 2.3).
- Async — catchAsync wrapper (yoki express-async-errors / Express 5 — 2.6).
- Operational vs programmer ni ajrating — operational: javob; programmer: log + ehtiyot 2.2-bob.
- 4 argument, eng oxirda 2.8-bob; 404 handler undan oldin 2.7-bob.
- Production'da texnik tafsilotni yashir (stack/DB — 14); to'liq log'da (2.10, 2.11).
- Tashqi xatolarni moslash (Zod/Mongoose to'g'ri status — 2.14).
- Process handlerlar (uncaughtException/unhandledRejection) + graceful shutdown + PM2 (2.12, 2.13).
- Xatolarni log qil (Winston/Pino — 5.12; Sentry — 10.9).
return next(err)—nextdan keyin kod ishlamasin.
9. Amaliy loyiha: "Professional Error Handling Tizimi"
Markazlashtirilgan, izchil error handling'ni mustahkamlash.
Maqsad
Custom error class, global handler, async wrapper, process-level handlerlar va xavfsiz xato javoblarini birlashtirib, barqaror, izchil xato tizimini qurish.
Talablar (requirements)
- Custom error class iyerarxiyasi:
AppError+NotFound/BadRequest/Unauthorized/Forbidden/Conflict(statusCode, isOperational — Misol 1, 2.3). - Async wrapper:
catchAsync(Misol 2, 2.6); route'lar try/catch'siz, faqat throw. - Global error handler: 4 argument, izchil javob 5.7-bob, prod'da tafsilotni yashiring (Misol 3, 2.10, 14).
- Tashqi xato moslash: Zod 5.9-bob 400, Mongoose CastError/duplicate (6) 400/409 2.14-bob.
- 404 handler: noma'lum yo'lga 2.7-bob; to'g'ri tartib (Misol 5, 2.8).
- Process handlerlar: unhandledRejection/uncaughtException + graceful shutdown (Misol 6, 2.12, 2.13).
- NODE_ENV xulq: dev'da stack, prod'da yashiring (5.8, 2.10).
- Operational vs programmer: ataylab ikkalasini yuzaga keltirib, handler farqini ko'rsating (Misol 8, 2.2).
- Logging: xatolarni log (console yoki Winston — 5.12); 5xx to'liq, 4xx qisqa.
- Route'lar toza bo'lsin — biznes logika + throw (markazlashgan — 2.1).
Maslahatlar (hint)
catchAsync—Promise.resolve(fn(...)).catch(next)(Misol 2).- Error handler 4 argument, app.js oxirida 2.8-bob.
- Prod'da:
statusCode >= 500 && isProd ? "Ichki xato" : message2.10-bob. - Tashqi xato:
err.name === "ZodError",err.code === 110002.14-bob. - Process:
uncaughtExceptiondaprocess.exit(1)2.12-bob. return next(err)—nextdan keyin davom etmasin.
"Tayyor" mezonlari (acceptance criteria)
- Custom error iyerarxiyasi (status, isOperational).
- catchAsync bilan async xatolar ushlanadi.
- Global handler izchil javob; prod'da tafsilot yashirin.
- Zod/Mongoose xatolari to'g'ri status'ga moslangan.
- 404 handler + to'g'ri tartib.
- Process handlerlar + graceful shutdown.
- dev/prod xato javobi farqi.
- Route'lar toza (try/catch'siz, faqat throw).
- Xatolar log qilinadi.
Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.
10. Xulosa va keyingi bobga ko'prik
Bu bobda barqaror backend'ning ustunini — error handlingni o'rgandik:
- Markazlashtirilgan — route'lar
throw/next(err); bitta global handler ushlaydi (toza, izchil — 2.1). - Operational (kutilgan — javob) vs programmer (bug — log + ehtiyot — 2.2).
- Custom error class (statusCode, isOperational — 2.3); global handler (4 argument, eng oxirda — 2.4, 2.8).
- Async —
catchAsyncwrapper (yoki express-async-errors / Express 5 — 2.6); 404 handler 2.7-bob. - Texnik tafsilotni yashir (prod — 14); tashqi xatolarni moslash (Zod/Mongoose — 2.14).
- Process handlerlar (uncaughtException/unhandledRejection) + graceful shutdown + PM2 (2.12, 2.13); log 5.12-bob.
Keyingi bob — 5.11-bob: File upload — Multer (lokal va cloud). Asosiy backend infratuzilmasini (server, REST, validatsiya, error) qurdik; endi amaliy, ko'p uchraydigan vazifani — fayl yuklash (rasm, hujjat) ni — Multer bilan o'rganamiz: lokal saqlash, cloud (S3 — 10.6), tur/hajm tekshiruvi (14), va 5.4'dagi stream'lar bilan.
Foydalanilgan rasmiy/ishonchli manbalar
- expressjs.com — Error Handling
- Toptal — Node.js Error Handling Best Practices (operational vs programmer)
- Better Stack — Express Error Handling Patterns; nodejs.org — process events
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!