Express middleware va next()

O’tgan darsda app.use(express.json()) qatorini yozdik va “hozircha shunday qabul qiling” dedik. Endi o’sha qator nima qilishini ochamiz. U middleware — Express’dagi eng kuchli tushuncha, chunki autentifikatsiya, log, xatolarni ushlash va forma o’qish — hammasi shu mexanizmga tayanadi.

Muammo: takrorlanadigan kod

Tasavvur qiling, har so’rovni terminalga yozib borishingiz kerak. Bir yo’li — har marshrutga console.log qo’shish:

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

app.get("/users", (request, response) => {
  console.log("GET /users");
  response.send("Foydalanuvchilar ro'yxati");
});

Yigirmata marshrutda bu yigirmata takror. Bittasini unutsangiz, log to’liq bo’lmaydi. Middleware shu muammoni bitta joyda yechadi.

Middleware nima

So’rov serverga kelganda zanjir bo’ylab yuradi:

So'rov → middleware 1 → middleware 2 → marshrut → javob

Har bo’g’in ikki ish qila oladi: so’rovni o’zgartirish yoki to’xtatish. express.json() birinchi turga kiradi — u so’rov tanasini o’qib, request.body ni to’ldiradi va zanjirni davom ettiradi.

Birinchi middleware

Log yozadigan funksiyani o’zimiz yozamiz:

const express = require("express");

const app = express();

// Har so'rov haqida terminalga yozamiz
app.use((request, response, next) => {
  console.log(`${request.method} ${request.url}`);
  next();
});

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

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

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

Ikki so’rov yuboring:

curl http://localhost:3000/tasks
curl http://localhost:3000/users

Serverning terminalida:

GET /tasks
GET /users

Marshrutlarda console.log yo’q, lekin ikkalasi ham qayd etildi. Yangi marshrut qo’shsangiz, u ham o’zidan-o’zi logga tushadi.

next() — zanjirning kaliti

next() chaqirilmasa nima bo’ladi? Sinab ko’ring:

// ❌ next() yo'q
app.use((request, response, next) => {
  console.log(`${request.method} ${request.url}`);
});

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

Terminalda GET /tasks chiqadi, lekin curl javob kutib osilib qoladi. Brauzerda ham sahifa cheksiz yuklanadi.

Zanjir tartibi

Middleware yozilgan tartibda ishlaydi. Tartibni ko’rish uchun ikkita qo’shamiz:

app.use((request, response, next) => {
  console.log("1-middleware boshlandi");
  next();
  console.log("1-middleware tugadi");
});

app.use((request, response, next) => {
  console.log("2-middleware");
  next();
});

app.get("/tasks", (request, response) => {
  console.log("Marshrut ishladi");
  response.send("Vazifalar ro'yxati");
});
curl http://localhost:3000/tasks
1-middleware boshlandi
2-middleware
Marshrut ishladi
1-middleware tugadi

Oxirgi qator diqqatga sazovor: next() navbatdagi funksiyani chaqiradi va u tugagach, boshqaruv qaytib keladi. Zanjir — bir tomonlama yo’l emas, ichma-ich chaqiruvlar.

Amaliy xulosa: app.use() marshrutlardan yuqorida turishi kerak. Pastda yozilsa, marshrut allaqachon javob yuborib bo’lgan bo’ladi va middleware ishlamaydi.

// ❌ Kech qoldi — marshrut oldin javob beradi
app.get("/tasks", (request, response) => {
  response.send("Vazifalar ro'yxati");
});

app.use(express.json());

Shu sababdan express.json() o’tgan darsda fayl boshida yozilgan edi.

So’rovga ma’lumot qo’shish

Middleware request obyektiga yangi maydon qo’sha oladi — keyingi bo’g’inlar uni o’qiydi:

app.use((request, response, next) => {
  // So'rov kelgan vaqtni belgilaymiz
  request.requestTime = new Date().toLocaleTimeString("uz-UZ");
  next();
});

app.get("/tasks", (request, response) => {
  response.send(`Vazifalar ro'yxati. So'rov vaqti: ${request.requestTime}`);
});
curl http://localhost:3000/tasks
Vazifalar ro'yxati. So'rov vaqti: 14:32:05

express.json() aynan shunday ishlaydi: tanani o’qib, request.body maydonini qo’yadi va next() ni chaqiradi.

Zanjirni to’xtatish

Middleware so’rovni davom ettirmasdan javob berib to’xtatishi ham mumkin. Bu tekshiruvlar uchun ishlatiladi:

// "/admin" bo'limiga faqat maxfiy kalit bilan kiriladi
app.use("/admin", (request, response, next) => {
  const key = request.query.key;

  if (key !== "secret123") {
    // next() chaqirilmaydi — zanjir shu yerda tugaydi
    return response.status(403).json({ error: "Ruxsat yo'q" });
  }

  next();
});

app.get("/admin/stats", (request, response) => {
  response.json({ users: 42, tasks: 128 });
});

Kalitsiz:

curl -i http://localhost:3000/admin/stats
HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8

{"error":"Ruxsat yo'q"}

Kalit bilan:

curl "http://localhost:3000/admin/stats?key=secret123"
{"users":42,"tasks":128}

403 — “kim ekaningiz aniq, lekin bu yerga ruxsatingiz yo’q”.

Marshrutga xos middleware

Middleware’ni bitta marshrutga ham ulash mumkin — uni app.get() ning o’rta argumenti sifatida yozasiz:

// Faqat shu marshrut uchun tekshiruv
function checkId(request, response, next) {
  const id = Number(request.params.id);

  if (Number.isNaN(id)) {
    return response.status(400).json({ error: "id son bo'lishi kerak" });
  }

  // Tekshirilgan sonni keyingi funksiyaga uzatamiz
  request.taskId = id;
  next();
}

app.get("/tasks/:id", checkId, (request, response) => {
  response.json({ id: request.taskId, title: "Kitob o'qish" });
});
curl -i http://localhost:3000/tasks/abc
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8

{"error":"id son bo'lishi kerak"}
curl http://localhost:3000/tasks/5
{"id":5,"title":"Kitob o'qish"}

Marshrut funksiyasi endi tekshiruv bilan shug’ullanmaydi — unga faqat to’g’ri son yetib keladi. Bir xil tekshiruvni bir nechta marshrutda ishlatish mumkin.

morgan — tayyor log middleware

Log yozadigan middleware’ni o’zimiz yozdik, lekin amalda tayyor paket ishlatiladi.

npm install morgan
const express = require("express");
const morgan = require("morgan");

const app = express();

// "dev" — qisqa va rangli format
app.use(morgan("dev"));

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

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

Server terminalida:

GET /tasks 200 3.412 ms - 18

Bitta qatorda usul, manzil, holat kodi, javob vaqti va hajmi bor. O’z qo’lingiz bilan yozgan versiyada bu ma’lumotlarning yarmi yo’q edi.

morgan ham oddiy middleware: ichida request, response va next bilan ishlaydigan o’sha funksiya turibdi. Uchinchi tomon paketlari sirli emas — faqat siz yozganidan puxtaroq.

Amaliy mashq

express-app loyihasida davom eting:

  1. Usul va manzilni terminalga yozadigan middleware’ni app.use() bilan ulang, ikki xil manzilga so’rov yuborib logni ko’ring;
  2. Shu middleware’dagi next() ni olib tashlang va curl javob kutib osilib qolishini kuzating, so’ng qaytarib qo’ying;
  3. Ikkita middleware qo’yib, next() dan keyin ham console.log yozing va chiqish tartibini tushuntiring;
  4. request.requestTime maydonini qo’shib, uni marshrut javobida chiqaring;
  5. /admin uchun kalit tekshiruvchi middleware yozing va uni kalitsiz hamda kalit bilan sinab ko’ring;
  6. morgan ni o’rnatib, app.use(morgan("dev")) qo’shing va o’z log’ingiz bilan solishtiring.

2-qadam eng qimmatlisi: next() unutilganda xato xabari chiqmaydi, shuning uchun alomatni oldindan tanib olish kerak.

Qisqacha xulosa

  • Middleware — so’rov marshrutga yetguncha ishlaydigan (request, response, next) funksiyasi.
  • app.use() uni zanjirga qo’shadi; manzil berilsa, faqat o’sha bo’limga ishlaydi.
  • next() chaqirilmasa so’rov osilib qoladi — xato xabarisiz.
  • Middleware ikki ishdan birini bajaradi: next() bilan davom ettiradi yoki javob yuborib to’xtatadi.
  • Zanjir yozilgan tartibda ishlaydi, shuning uchun app.use() marshrutlardan yuqorida turadi.
  • Middleware request ga yangi maydon qo’sha oladi — express.json() aynan shunday request.body ni to’ldiradi.
  • Uchinchi tomon middleware’i (morgan) o’zingiz yozganidek ishlaydi, faqat puxtaroq.

Keyingi darsda statik fayllar — HTML, CSS va rasmlarni serverdan berish, bu ham middleware orqali bajariladi.

Bu dars foydali bo'ldimi?

marta ko'rildi