Express xatolarni boshqarish

Hozirgacha yozgan kodimiz hamma narsa joyida ketishiga ishonadi. Lekin foydalanuvchi mavjud bo’lmagan manzilni so’raydi, id o’rniga harf yozadi, fayl o’qilmay qoladi. Bu holatlarni oldindan qamramasangiz, Express o’zining xunuk standart javobini beradi — yoki bundan yomoni, server butunlay to’xtaydi.

Standart javob nimasi bilan yomon

Marshrutlash darsida ko’rgan javobni eslang:

curl http://localhost:3000/hello
<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8"><title>Error</title></head>
<body><pre>Cannot GET /hello</pre></body>
</html>

Ikki muammo bor. Birinchisi — javob inglizcha HTML, sayt tilida emas. Ikkinchisi jiddiyroq: agar bu API bo’lsa, mijoz JSON kutgan edi, HTML keldi. response.json() bilan o’qishga urinsa, xato chiqadi.

O’z 404 javobingiz

Yechim — hamma marshrutdan keyin turadigan app.use():

const express = require("express");

const app = express();

app.get("/tasks", (request, response) => {
  response.send("Vazifalar ro'yxati");
});

// Yuqoridagi marshrutlarning hech biri mos kelmasa, shu yerga tushadi
app.use((request, response) => {
  response.status(404).json({ error: "Bunday manzil topilmadi" });
});

app.listen(3000, () => {
  console.log("Server ishga tushdi: http://localhost:3000");
});
curl -i http://localhost:3000/hello
HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8

{"error":"Bunday manzil topilmadi"}

Mexanizm middleware darsidan tanish: Express zanjirni tartib bilan yuradi. So’rov hamma marshrutdan o’tib, hech qayerda javob olmasa, oxirgi app.use() ga yetib keladi.

Xato middleware’i: to’rt parametr

404 — “topilmadi”. Undan boshqa xatolar ham bor: kod ichida nimadir buzildi. Express ularni alohida turdagi middleware bilan ushlaydi.

Bu Express’dagi eng ko’p e’tibordan chetda qoladigan tafsilot:

// ❌ Uch parametr — oddiy middleware, xatoni ushlamaydi
app.use((request, response, next) => { });

// ✅ To'rt parametr — xato middleware'i
app.use((err, request, response, next) => { });

To’liq misol:

const express = require("express");

const app = express();

app.get("/tasks", (request, response) => {
  response.send("Vazifalar ro'yxati");
});

// 404 — manzil topilmadi
app.use((request, response) => {
  response.status(404).json({ error: "Bunday manzil topilmadi" });
});

// Xato ishlovchisi — hammasidan keyin
app.use((err, request, response, next) => {
  // Tafsilotni faqat serverning terminaliga yozamiz
  console.error(err.message);

  response.status(500).json({ error: "Serverda xato yuz berdi" });
});

app.listen(3000, () => {
  console.log("Server ishga tushdi: http://localhost:3000");
});

Tartib qat’iy: marshrutlar → 404 → xato middleware’i.

next(err) bilan xatoni uzatish

Xato middleware’iga qanday borib tushiladi? next() ga argument berib.

const tasks = [
  { id: 1, title: "Kitob o'qish", isDone: false },
  { id: 2, title: "Kod yozish", isDone: true },
];

app.get("/api/tasks/:id", (request, response, next) => {
  const id = Number(request.params.id);

  if (Number.isNaN(id)) {
    // Foydalanuvchi xatosi — darhol javob beramiz
    return response.status(400).json({ error: "id son bo'lishi kerak" });
  }

  const task = tasks.find((item) => item.id === id);

  if (!task) {
    return response.status(404).json({ error: "Vazifa topilmadi" });
  }

  response.json(task);
});

Qoidani eslab qoling:

next() shakli Nima bo’ladi
next() Navbatdagi oddiy middleware’ga o’tadi
next(err) To’g’ridan-to’g’ri xato middleware’iga sakraydi

next(err) chaqirilganda oradagi hamma oddiy middleware chetlab o’tiladi. Buni ko’rish uchun ataylab xato chiqaramiz:

app.get("/boom", (request, response, next) => {
  const error = new Error("Sinov uchun ataylab chiqarilgan xato");
  next(error);
});
curl -i http://localhost:3000/boom
HTTP/1.1 500 Internal Server Error
Content-Type: application/json; charset=utf-8

{"error":"Serverda xato yuz berdi"}

Server terminalida esa:

Sinov uchun ataylab chiqarilgan xato

Foydalanuvchi umumiy xabarni, siz aniq sababni ko’rdingiz.

Sinxron xato o’zi ushlanadi

Marshrut ichida oddiy xato yuz bersa, Express uni o’zi tutadi:

app.get("/sync-error", (request, response) => {
  // Mavjud bo'lmagan funksiya chaqirilyapti
  const result = calculateTotal();
  response.json({ result: result });
});

Bu manzilni so’rasangiz, server yiqilmaydi — xato middleware’i ishlaydi va 500 qaytaradi. Express marshrut funksiyasini try/catch ichida chaqiradi.

Lekin bu himoya faqat sinxron kodga tegishli.

Async marshrutdagi tuzoq

Asinxron kodda vaziyat boshqacha:

const fs = require("fs/promises");

// ❌ Xato ushlanmaydi
app.get("/report", async (request, response) => {
  const text = await fs.readFile("report.txt", "utf-8");
  response.send(text);
});

report.txt fayli bo’lmasa, readFile xato beradi. Express uni ko’rmaydi, chunki xato async funksiya ichidagi Promise’da yuz beradi.

Yechim — try/catch va next(error):

const fs = require("fs/promises");

// ✅ Xato ushlanadi va uzatiladi
app.get("/report", async (request, response, next) => {
  try {
    const text = await fs.readFile("report.txt", "utf-8");
    response.send(text);
  } catch (error) {
    next(error);
  }
});

Fayl bo’lmasa:

curl -i http://localhost:3000/report
HTTP/1.1 500 Internal Server Error
Content-Type: application/json; charset=utf-8

{"error":"Serverda xato yuz berdi"}

Server ishlashda davom etadi. try/catch va async/await ishlashi async/await darsida va xatolar darsida ko’rilgan.

Holat kodini xatoga biriktirish

Hamma xato 500 emas. Kodni xato obyektiga yozib qo’yish mumkin:

app.get("/api/tasks/:id", (request, response, next) => {
  const id = Number(request.params.id);

  if (Number.isNaN(id)) {
    const error = new Error("id son bo'lishi kerak");
    error.status = 400;
    return next(error);
  }

  const task = tasks.find((item) => item.id === id);

  if (!task) {
    const error = new Error("Vazifa topilmadi");
    error.status = 404;
    return next(error);
  }

  response.json(task);
});

// Xato middleware'i kodni o'qiydi
app.use((err, request, response, next) => {
  const status = err.status || 500;

  // 500 bo'lsa — bizning xatomiz, terminalga to'liq yozamiz
  if (status === 500) {
    console.error(err);
  }

  response.status(status).json({ error: err.message });
});

Bu yerda err.message javobga tushyapti — lekin faqat biz o’zimiz yozgan xabarlar uchun. 500 holatida xabar kutilmagan manbadan kelishi mumkin, shuning uchun uni umumiy matnga almashtirish xavfsizroq:

app.use((err, request, response, next) => {
  const status = err.status || 500;

  if (status === 500) {
    console.error(err);
    return response.status(500).json({ error: "Serverda xato yuz berdi" });
  }

  response.status(status).json({ error: err.message });
});
curl -i http://localhost:3000/api/tasks/abc
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8

{"error":"id son bo'lishi kerak"}

To’liq tartib

Yakuniy fayl tuzilishi shunday bo’ladi:

const express = require("express");

const app = express();

app.use(express.json());          // 1. Kirish middleware'lari
app.get("/tasks", handler);       // 2. Marshrutlar
app.use(notFoundHandler);         // 3. 404
app.use(errorHandler);            // 4. Xato ishlovchisi

app.listen(3000);

Yuqoridagi qatorlardagi handler, notFoundHandler va errorHandler — oldingi bo’limlarda yozilgan funksiyalar. Tartib o’zgarsa, tizim buziladi: 404 yuqorida bo’lsa hamma so’rovni yutadi, xato middleware’i yuqorida bo’lsa hech qachon chaqirilmaydi.

Amaliy mashq

express-app loyihasida davom eting:

  1. Hamma marshrutdan keyin 404 middleware’ini qo’shib, mavjud bo’lmagan manzilni curl -i bilan so’rang;
  2. 404 middleware’ini marshrutlardan yuqoriga ko’chiring va hamma so’rov 404 olishini ko’ring, so’ng joyiga qaytaring;
  3. To’rt parametrli xato middleware’ini yozing va /boom marshrutida next(new Error("...")) bilan sinang;
  4. Xato middleware’idan bitta parametrni olib tashlab, u ishlamay qolishini tekshiring;
  5. fs/promises bilan mavjud bo’lmagan faylni o’qiydigan async marshrut yozing — avval try/catch siz, keyin u bilan;
  6. error.status = 404 biriktirib, xato middleware’i to’g’ri kodni qaytarishini tasdiqlang.

4-qadam eng muhimi: xato middleware’i parametrlar soni bilan aniqlanishini bir marta ko’rsangiz, uni boshqa unutmaysiz.

Qisqacha xulosa

  • Standart Cannot GET javobi inglizcha HTML — API uchun yaramaydi.
  • 404 middleware’i hamma marshrutdan keyin, app.listen() dan oldin turadi.
  • Xato middleware’i to’rt parametrli bo’lishi shart: (err, request, response, next).
  • next(err) oddiy middleware’larni chetlab, to’g’ridan-to’g’ri xato ishlovchisiga o’tadi.
  • Sinxron xatoni Express o’zi ushlaydi, async marshrutda esa try/catch va next(error) sizning zimmangizda.
  • Xato tafsiloti va stack faqat terminalga yoziladi — foydalanuvchiga umumiy xabar boradi.
  • err.status biriktirilsa, bitta ishlovchi turli holat kodlarini qaytara oladi.

Keyingi darsda CRUD API — beshta endpoint yozib, ma’lumot qo’shish, o’qish, yangilash va o’chirishni amalda ko’ramiz.

Bu dars foydali bo'ldimi?

marta ko'rildi