IlmHamroh
Dasturlash kitobi (eski nashr)/5-QISM — Nodejs5/23-dars17 daqiqa
Mundarija (36)

Node.js http moduli — Express'siz server yaratish (5.5-bob)

5-QISM — Node.js Backend · 5-mavzu


1. Kirish va motivatsiya

0.4-bobda HTTP nazariyasini (client-server, so'rov/javob, status kodlar, metodlar) o'rgandik. 5.1–5.4-boblarda Node mexanizmlarini (event loop, core modullar, stream/event) ko'rdik. Endi hammasini birlashtiramiz: faqat core http modul bilan, Express'siz, o'z qo'limiz bilan server yaratamiz.

"Nega Express'siz? Hamma Express ishlatadi-ku!" — to'g'ri, real loyihada Express 5.6-bob yoki NestJS (8) ishlatasiz. Lekin Express — http modulning o'rami (wrapper). Express "sehrini" tushunish uchun, pardaning ortida nima borligini bilish kerak: so'rov qanday keladi, javob qanday yuboriladi, routing qanday ishlaydi, body qanday o'qiladi. Bu bobni o'tgandan keyin Express sizga "sehr" emas, "qulaylik" bo'lib ko'rinadi.

http modul — Node'ning eng muhim core moduli 5.3-bob: u TCP server yaratadi, HTTP protokolini 0.4-bob parse qiladi va sizga req/res obyektlarini beradi. Va eng muhimi: req — Readable stream, res — Writable stream 5.4-bob! Ya'ni 5.4-bob bevosita shu yerda ishlaydi.

O'xshatish: http modul — restoranni noldan qurish: o'zingiz eshik ochasiz, mehmonni kutib olasiz, buyurtmani yozib olasiz, taom tayyorlaysiz, olib chiqasiz. Express 5.6-bob — tayyor restoran tizimi (ofitsiantlar, oshxona tartibi). Avval noldan qurishni bilsangiz, tayyor tizimni ham chuqur tushunasiz.

Nega muhim?

  • Express/NestJS poydevori — ular http ustiga qurilgan; ichini bilish — chuqur tushunish.
  • HTTP'ni amalda — 0.4 nazariyasi kodga aylanadi (so'rov/javob/status/header).
  • Stream/event (5.4) — req/res aynan shular.
  • Routing, body parsing, status — Express'da avtomatik bo'lgan narsalar ichini ko'rasiz.

2. Nazariya — chuqur tushuntirish

2.1. http modul nima qiladi

http (5.3: core modul) — createServer bilan TCP server yaratadi (0.4: TCP/port). U pardaning ortida (nodejs.org):

  1. Belgilangan portni tinglaydi (0.2: port, 0.4).
  2. Ulanish kelganda HTTP protokolini (0.4) parse qiladi (matn → obyekt).
  3. Har so'rov uchun request eventini chiqaradi (5.4: EventEmitter), sizga req/res beradi.
js
import http from "node:http";

const server = http.createServer((req, res) => {
  // Bu funksiya HAR so'rovda chaqiriladi (5.4: event handler)
  res.end("Salom, dunyo!");
});

server.listen(3000, () => {
  console.log("Server http://localhost:3000 da");   // (0.4: localhost, port)
});

2.2. createServer va request handler

createServer(handler) — handler har so'rovda chaqiriladi (5.1: event loop'da; bitta thread minglab so'rovni — 5.1):

text
  Brauzer/client → so'rov 0.4-bob → Node http parse → handler(req, res)
                                                      ↓
  Brauzer ← javob 0.4-bob ←──────────────── res.end(...)

createServer aslida EventEmitter 5.4-bob: http.createServer(handler) — server.on("request", handler) ning qisqasi. Server — EventEmitter; "request" — event.

2.3. req — IncomingMessage (Readable stream — 5.4)

req — http.IncomingMessage (Readable stream — 5.4): kiruvchi so'rov ma'lumotini saqlaydi 0.4-bob:

js
req.method       // "GET" / "POST" / ... (0.4: metod)
req.url          // "/users?page=2" (path + query — 0.4: URL)
req.headers      // { host, "content-type", authorization, ... } (0.4: header)
req.httpVersion  // "1.1"
// req — Readable stream → body uchun "data"/"end" eventlari (2.5, 5.4)

req.url — faqat path+query (host'siz): /users?page=2 0.4-bob. To'liq URL emas. Query (?page=2) ni ajratish uchun parse kerak 2.7-bob.

2.4. res — ServerResponse (Writable stream — 5.4)

res — http.ServerResponse (Writable stream — 5.4): javobni yuboradi 0.4-bob:

js
res.writeHead(200, { "Content-Type": "application/json" });  // status + header (0.4)
res.statusCode = 200;                  // status alohida (0.4)
res.setHeader("X-Custom", "qiymat");   // header alohida
res.write("qism");                     // body qismi (stream — 5.4)
res.end("oxirgi qism");                // YAKUNLASH (majburiy! 5.4)

res.end() MAJBURIY — har javobni yakunlash kerak (nodejs.org, 5.4: Writable). end chaqirilmasa — brauzer kutib qoladi (so'rov "osilib" qoladi). Va writeHead write/end'dan oldin chaqirilishi kerak.

2.5. Status kodlar va headerlar (0.4 amaliyoti)

0.4-bobdagi status kodlar (2xx/4xx/5xx) endi kodda:

js
res.writeHead(200, {...});   // OK
res.writeHead(201, {...});   // Created (POST muvaffaqiyatli — 0.4)
res.writeHead(404, {...});   // Not Found (0.4)
res.writeHead(400, {...});   // Bad Request (0.4)
res.writeHead(500, {...});   // Internal Server Error (0.4)

Muhim headerlar: Content-Type (javob turi — application/json, text/html), Content-Length, Cache-Control, CORS 5.20-bob.

Connection: keep-alive 0.4-bob: HTTP/1.1'da ulanish qayta ishlatiladi — bitta TCP ulanish ustida ketma-ket bir nechta so'rov ketadi (har so'rovga yangi ulanish ochilmaydi → tezroq). Node'ning http serveri buni avtomatik qiladi; siz alohida sozlamaysiz. req.headers.connection orqali ko'rishingiz mumkin. Mijoz tomonida (http.request) ko'p so'rov yuborsangiz, ulanishni qayta ishlatish uchun http.Agent({ keepAlive: true }) ishlatiladi.

2.6. Routing — qo'lda (req.url + req.method)

Express'da app.get("/users", ...) avtomatik; http'da qo'lda req.url va req.methodni tekshirasiz (nodejs.org):

js
const server = http.createServer((req, res) => {
  if (req.method === "GET" && req.url === "/") {
    res.writeHead(200).end("Bosh sahifa");
  } else if (req.method === "GET" && req.url === "/users") {
    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify([{ id: 1, ism: "Ali" }]));   // (2.8: JSON)
  } else {
    res.writeHead(404).end("Topilmadi");                 // (0.4: 404)
  }
});

Bu — Express routerning "ichi". Ko'p route bo'lsa, bu if/else zanjiri chalkashadi — aynan shuning uchun Express 5.6-bob keladi.

2.7. Query parametrlarni parse qilish (0.4: URL)

req.url — /users?page=2&limit=10; query'ni ajratish uchun URL (5.3, 2.17):

js
const url = new URL(req.url, `http://${req.headers.host}`);   // to'liq URL (5.3)
url.pathname;                       // "/users" (query'siz)
url.searchParams.get("page");       // "2" (0.4: query)
url.searchParams.get("limit");      // "10"

2.8. Request body'ni o'qish (POST — stream! — 5.4)

Eng muhim qism: req — Readable stream (2.3, 5.4). POST body bo'lak-bo'lak (chunk) keladi; uni data/end eventlari bilan yig'amiz 5.4-bob:

js
function bodyOqi(req) {
  return new Promise((resolve, reject) => {        // (2.11: Promise)
    let body = "";
    req.on("data", (chunk) => { body += chunk; }); // chunk yig'ish (5.4)
    req.on("end", () => resolve(body));             // tugadi (5.4)
    req.on("error", reject);                        // xato (5.4: error!)
  });
}

// Ishlatish (POST'da)
const xom = await bodyOqi(req);
const data = JSON.parse(xom);    // matn → obyekt (2.8)

Body avtomatik kelmaydi! req.body — http'da yo'q (Express'da express.json() middleware qo'shadi — 5.6). Sof http'da body'ni qo'lda, stream chunk'larini yig'ib o'qiysiz 5.4-bob. Bu — Express body-parser'ning "ichi".

2.9. JSON javob qaytarish (API uchun)

js
function jsonJavob(res, status, data) {
  res.writeHead(status, { "Content-Type": "application/json" });   // (2.5)
  res.end(JSON.stringify(data));    // obyekt → matn (2.8)
}
jsonJavob(res, 200, { ism: "Ali" });
jsonJavob(res, 404, { xato: "Topilmadi" });

2.10. Static fayl xizmati (stream bilan — 5.4)

HTML/CSS/rasm faylni yuborish — stream bilan (5.4: xotira-samarali):

js
import { createReadStream } from "node:fs";
import path from "node:path";

if (req.url === "/index.html") {
  res.writeHead(200, { "Content-Type": "text/html" });
  createReadStream(path.join(import.meta.dirname, "index.html")).pipe(res);  // (5.4)
}

2.11. http.request — client sifatida (so'rov yuborish)

http faqat server emas — client ham (boshqa API'ga so'rov — 5.18: SMS). Lekin zamonaviy kodda fetch (2.17, Node'da bor) yoki Axios 2.18-bob qulayroq:

js
// Zamonaviy: Node'da fetch (2.17)
const res = await fetch("https://api.example.com/data");
const data = await res.json();
// http.request — past darajali, kamdan-kam to'g'ridan ishlatiladi

2.12. HTTP vs HTTPS (shifrlangan ulanish — 0.4)

http modul — shifrlanmagan ulanish (0.4: ma'lumot ochiq matnda ketadi). Productionda (10) har doim HTTPS kerak: u TLS sertifikat bilan ulanishni shifrlaydi (parol/token o'rtada ushlab olinmaydi). Node'da https core modul bor — interfeysi http bilan bir xil, faqat sertifikat (key/cert) qo'shiladi:

js
import https from "node:https";
import { readFileSync } from "node:fs";

const ssl = {
  key: readFileSync("private-key.pem"),    // maxfiy kalit
  cert: readFileSync("certificate.pem"),   // sertifikat
};
https.createServer(ssl, (req, res) => {    // qolgani http bilan AYNAN bir xil
  res.end("Xavfsiz (TLS) ulanish");
}).listen(443);                             // HTTPS standart porti — 443 (0.4)

Amalda sertifikatni to'g'ridan kodda boshqarmaysiz: HTTPS'ni odatda reverse proxy (Nginx) yoki bulut platformasi (10) hal qiladi — Node serveringiz oddiy http'da qoladi, TLS esa undan oldinda "tugaydi" (TLS termination). Bepul sertifikat uchun — Let's Encrypt.

2.13. Nega Express? (http'ning kamchiliklari)

Sof http bilan ishlaganda quyidagilarni qo'lda qilasiz (zerikarli, xatoga moyil):

  • Routing — if/else zanjiri 2.6-bob — ko'p route'da chalkash.
  • Body parsing — har safar stream o'qish 2.8-bob.
  • Query/params — qo'lda parse 2.7-bob.
  • Middleware yo'q — umumiy logika (auth, log) takrorlanadi.
  • Status/header — qo'lda.

Express (5.6) — bularning hammasini avtomatlashtiradi: app.get("/users/:id", ...), req.body, req.params, middleware. Lekin u http ustiga qurilgan — shuning uchun ichini bilish muhim.

2.14. Production Server Nozikliklari: Keep-Alive Timeouts, Slowloris va True Graceful Shutdown

1. Nginx / AWS ALB bilan Keep-Alive Race Condition (502 Bad Gateway tuzog'i)

Agar Node.js serveringiz Nginx yoki AWS ALB (Application Load Balancer) orqasida ishlayotgan bo'lsa, Node.js serveringizning keepAliveTimeout qiymati yuklama muvozanatlovchi (Load Balancer) ning timeout qiymatidan KATTA bo'lishi shart!

text
Muammo: Nginx (timeout 65s)  Node.js (default keepAliveTimeout 5s)
Nginx TCP ulanishni ochiq deb hisoblab yangi so'rov yuboradi,
lekin Node.js ayni shu millisekundda ulanishni yopadi (FIN yuboradi).
Natija mijozga: 502 Bad Gateway (Connection reset by peer)!

Production sozlamasi:

js
const server = http.createServer(handler);

// Agar Nginx keepalive_timeout 65s bo'lsa:
server.keepAliveTimeout = 66000; // 66 sekund (Nginx'dan katta bo'lishi shart!)
server.headersTimeout = 67000;   // keepAliveTimeout'dan doim 1-2 soniya katta bo'lishi kerak

2. Slowloris DoS hujumi va Server Timeouts

Hujumchi serverga ulanish ochib, HTTP sarlavhalarini soniyasiga 1 baytdan juda sekin yuboradi. Barcha socketlar band bo'lib, haqiqiy foydalanuvchilar kira olmay qoladi. Node.js buni oldini olish uchun taymerlar beradi:

js
server.requestTimeout = 30000; // Butun so'rov maksimal 30s ichida yakunlanishi shart
server.headersTimeout = 10000; // Sarlavhalar 10s ichida to'liq kelishi shart

3. Mukammal Graceful Shutdown (Haqiqiy toza to'xtatish)

Klassik server.close() chaqirilganda, ochiq bo'lgan keep-alive ulanishlar yopilmagani sababli jarayon uzoq vaqt "osilib" qolishi mumkin. Node 18.2+ versiyasidan boshlab maxsus yechim kiritilgan:

js
function gracefulShutdown() {
  console.log("SIGTERM qabul qilindi. Server to'xtatilmoqda...");

  // 1. Yangi ulanishlarni qabul qilishni to'xtatish
  server.close((err) => {
    if (err) {
      console.error("Yopilishda xato:", err);
      process.exit(1);
    }
    console.log("Barcha faol so'rovlar yakunlandi. Chiqilmoqda.");
    process.exit(0);
  });

  // 2. Yangi bo'sh turgan (idle) keep-alive ulanishlarni zudlik bilan yopish
  if (typeof server.closeIdleConnections === "function") {
    server.closeIdleConnections();
  }

  // 3. Agar 10 sekund ichida faol so'rovlar tugamasa, majburiy to'xtatish (Force Exit)
  setTimeout(() => {
    console.error("Majburiy to'xtatish (Timeout)!");
    process.exit(1);
  }, 10000).unref(); // unref() Event Loopni ushlab turmaydi
}

process.on("SIGTERM", gracefulShutdown);
process.on("SIGINT", gracefulShutdown);

3. Sintaksis — tez ma'lumotnoma

js
import http from "node:http";

const server = http.createServer((req, res) => {
  // req (Readable — 5.4): req.method, req.url, req.headers
  // res (Writable — 5.4): res.writeHead(status, headers), res.write(), res.end()
});
server.listen(3000, cb);

// Query (5.3)
const url = new URL(req.url, `http://${req.headers.host}`);
url.pathname;  url.searchParams.get("x");

// Body (stream — 5.4, 2.8)
req.on("data", c => body += c);  req.on("end", () => JSON.parse(body));

// JSON javob
res.writeHead(200, {"Content-Type":"application/json"});
res.end(JSON.stringify(data));

4. Batafsil kod namunalari

Misol 1 — Eng oddiy server (2.1)

js
import http from "node:http";

const server = http.createServer((req, res) => {
  console.log(`${req.method} ${req.url}`);   // har so'rovni loglang (0.4)
  res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
  res.end("Salom, backend dunyosi!");        // (2.4: end majburiy)
});

server.listen(3000, () => {
  console.log("Server http://localhost:3000 da ishlayapti");
});
// node server.js → brauzerda localhost:3000

Misol 2 — Qo'lda routing (2.6)

js
import http from "node:http";

const server = http.createServer((req, res) => {
  res.setHeader("Content-Type", "application/json; charset=utf-8");

  // Routing — req.method + req.url (2.6)
  if (req.method === "GET" && req.url === "/") {
    res.writeHead(200).end(JSON.stringify({ xabar: "Bosh sahifa" }));
  } else if (req.method === "GET" && req.url === "/health") {
    res.writeHead(200).end(JSON.stringify({ holat: "ok", vaqt: Date.now() }));
  } else {
    res.writeHead(404).end(JSON.stringify({ xato: "Sahifa topilmadi" }));  // (0.4: 404)
  }
});
server.listen(3000);

Misol 3 — Query parametrlar (2.7)

js
const server = http.createServer((req, res) => {
  const url = new URL(req.url, `http://${req.headers.host}`);   // (5.3, 2.7)

  if (url.pathname === "/qidiruv") {
    const q = url.searchParams.get("q") ?? "";          // ?q=telefon (0.4)
    const sahifa = Number(url.searchParams.get("page") ?? 1);   // (2.6: Number)
    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify({ qidiruv: q, sahifa }));
  } else {
    res.writeHead(404).end("Topilmadi");
  }
});
// localhost:3000/qidiruv?q=telefon&page=2 → {"qidiruv":"telefon","sahifa":2}

Misol 4 — POST body o'qish (stream — 2.8, 5.4)

js
import http from "node:http";

// Body'ni stream chunk'laridan yig'ish (5.4)
function bodyOqi(req) {
  return new Promise((resolve, reject) => {
    let body = "";
    req.on("data", (chunk) => {
      body += chunk;
      if (body.length > 1e6) {       // 1MB chegara (DoS himoyasi — 14)
        reject(new Error("Body juda katta"));
        req.destroy();
      }
    });
    req.on("end", () => resolve(body));
    req.on("error", reject);          // (5.4: error)
  });
}

const server = http.createServer(async (req, res) => {
  if (req.method === "POST" && req.url === "/users") {
    try {
      const xom = await bodyOqi(req);          // body yig'ish (2.8)
      const user = JSON.parse(xom);            // matn → obyekt (2.8)
      // ... validatsiya, DB ... (5.9, 6)
      res.writeHead(201, { "Content-Type": "application/json" });   // 201 Created (0.4)
      res.end(JSON.stringify({ id: 1, ...user }));
    } catch (err) {
      res.writeHead(400, { "Content-Type": "application/json" });   // 400 (0.4)
      res.end(JSON.stringify({ xato: "Noto'g'ri JSON" }));          // (2.13)
    }
  } else {
    res.writeHead(404).end();
  }
});
server.listen(3000);

Misol 5 — Mini REST API (CRUD — 0.4, 6 ga ko'prik)

js
import http from "node:http";

let users = [{ id: 1, ism: "Ali" }];   // xotirada (keyin DB — 6)
let keyingiId = 2;

const bodyOqi = (req) => new Promise((res) => {
  let b = ""; req.on("data", c => b += c); req.on("end", () => res(b));
});

const server = http.createServer(async (req, res) => {
  res.setHeader("Content-Type", "application/json");
  const url = new URL(req.url, `http://${req.headers.host}`);
  const segments = url.pathname.split("/").filter(Boolean);   // ["users","1"]

  // GET /users — ro'yxat (0.4: GET)
  if (req.method === "GET" && url.pathname === "/users") {
    res.writeHead(200).end(JSON.stringify(users));
  }
  // GET /users/:id — bitta (2.7)
  else if (req.method === "GET" && segments[0] === "users" && segments[1]) {
    const user = users.find(u => u.id === Number(segments[1]));   // (2.7: find)
    if (user) res.writeHead(200).end(JSON.stringify(user));
    else res.writeHead(404).end(JSON.stringify({ xato: "Topilmadi" }));
  }
  // POST /users — yaratish (0.4: POST → 201)
  else if (req.method === "POST" && url.pathname === "/users") {
    const yangi = { id: keyingiId++, ...JSON.parse(await bodyOqi(req)) };
    users.push(yangi);
    res.writeHead(201).end(JSON.stringify(yangi));
  }
  // DELETE /users/:id (0.4: DELETE)
  else if (req.method === "DELETE" && segments[0] === "users") {
    users = users.filter(u => u.id !== Number(segments[1]));   // (2.7)
    res.writeHead(204).end();    // 204 No Content (0.4)
  }
  else res.writeHead(404).end(JSON.stringify({ xato: "Yo'l topilmadi" }));
});
server.listen(3000, () => console.log("API: localhost:3000/users"));

Misol 6 — Static fayl + HTML (2.10, 5.4)

js
import http from "node:http";
import { createReadStream } from "node:fs";
import path from "node:path";

const MIME = { ".html": "text/html", ".css": "text/css", ".js": "text/javascript" };

const server = http.createServer((req, res) => {
  const fayl = req.url === "/" ? "/index.html" : req.url;
  const yol = path.join(import.meta.dirname, "public", fayl);   // (5.3)
  const tur = MIME[path.extname(fayl)] ?? "application/octet-stream";

  const stream = createReadStream(yol);
  stream.on("error", () => {                  // fayl yo'q (5.4: error)
    res.writeHead(404).end("Fayl topilmadi");
  });
  stream.once("open", () => {                  // fayl bor (5.4: once)
    res.writeHead(200, { "Content-Type": tur });
    stream.pipe(res);                          // stream bilan yuborish (5.4)
  });
});
server.listen(3000);

Misol 7 — Graceful shutdown (server'ni to'g'ri to'xtatish)

js
const server = http.createServer((req, res) => res.end("ok"));
server.listen(3000);

// Process to'xtatilganda (Ctrl+C / deploy) — yangi so'rovni qabul qilmay, joriylarni tugat
process.on("SIGTERM", () => {                  // (5.1: process events, 0.3: signal)
  console.log("Server yopilmoqda...");
  server.close(() => {                          // joriy so'rovlarni tugatib yopadi
    console.log("Server toza yopildi");
    process.exit(0);                            // (5.1)
  });
});
// Production'da muhim (10): deploy paytida so'rovlar yo'qolmaydi

5. To'g'ri va noto'g'ri holatlar

1) res.end()ni unutish

js
// ❌ javob yakunlanmadi → brauzer kutib qoladi (so'rov osiladi — 2.4)
res.write("salom");

// ✅ end bilan yakunlang
res.end("salom");

2) req.bodyni to'g'ridan kutish

js
// ❌ http'da req.body YO'Q (Express'da bor — 2.8)
const data = req.body;   // undefined

// ✅ stream'dan qo'lda o'qing (5.4)
const data = JSON.parse(await bodyOqi(req));

3) writeHeadni write/enddan keyin

js
// ❌ header body'dan keyin yuborib bo'lmaydi (2.4)
res.end("salom");
res.writeHead(200);   // ERR_STREAM_WRITE_AFTER_END

// ✅ writeHead birinchi
res.writeHead(200);
res.end("salom");

4) JSON javobda Content-Type'siz

js
// ❌ brauzer matn deb o'ylaydi (0.4)
res.end(JSON.stringify(data));

// ✅ Content-Type bering
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify(data));

5) Body o'lchamini cheklamaslik (DoS — 14)

js
// ❌ cheksiz body → xotira to'ladi (hujum — 14)
req.on("data", c => body += c);

// ✅ chegara qo'ying (Misol 4)
if (body.length > 1e6) { req.destroy(); }

6. Keng tarqalgan xatolar va yechimlari

Xato 1 — EADDRINUSE: address already in use :::3000

Sababi: port band (0.2, 0.4, 5.1). Yechimi: boshqa port; band process'ni to'xtating (0.3: lsof/netstat + kill).

Xato 2 — Brauzer cheksiz yuklanadi (spinner)

Sababi: res.end() chaqirilmagan 2.4-bob. Yechimi: har yo'lda res.end(); routing'da else (404) bo'lsin.

Xato 3 — ERR_STREAM_WRITE_AFTER_END

Sababi: res.end()dan keyin yana yozish, yoki writeHead kech 2.4-bob. Yechimi: enddan keyin yozmang; writeHead birinchi.

Xato 4 — req.body undefined

Sababi: body avtomatik parse qilinmaydi 2.8-bob. Yechimi: stream'dan o'qing (Misol 4) yoki Express + express.json() 5.6-bob.

Xato 5 — JSON parse xatosi (POST)

Sababi: noto'g'ri/bo'sh body (2.8, 2.13). Yechimi: try/catch + 400 javob (Misol 4).

Xato 6 — Cyrillic/o'zbek matn buzilib ko'rinadi

Sababi: charset yo'q (0.1: UTF-8). Yechimi: Content-Type: text/html; charset=utf-8.


7. Integratsiya — bu mavzu stack'ning qayerida uchraydi

  • HTTP nazariyasi 0.4-bob: metod/status/header/URL — bu yerda kodga aylandi.
  • Stream/Event 5.4-bob: req (Readable), res (Writable), data/end.
  • Express 5.6-bob: http ustiga qurilgan — routing/body/middleware avtomatlashtiradi.
  • REST API 5.7-bob: Misol 5 — REST asoslari.
  • Validatsiya 5.9-bob: body o'qigach tekshirish.
  • Xavfsizlik (5.20, 14): body o'lchami, CORS, headerlar.
  • Deploy (10): graceful shutdown (Misol 7).

8. Eng yaxshi amaliyotlar (best practices)

  • Har yo'lda res.end() — javobni yakunlang; routing'da else 404 2.4-bob.
  • writeHead (status+header) write/enddan oldin 2.4-bob.
  • JSON'da Content-Type: application/json + charset=utf-8 (0.1, 0.4).
  • Body'ni stream'dan o'qing (req.body yo'q — 2.8); o'lchamni cheklang (DoS — 14).
  • To'g'ri status kodlar (201 Created, 204 No Content, 404, 400 — 0.4).
  • error event'ini boshqaring (req/res streamlar — 5.4).
  • Graceful shutdown (server.close — Misol 7) — production (10).
  • Real loyihada Express/NestJS (5.6, 8) — httpni faqat o'rganish/maxsus holat uchun 2.13-bob.

9. Amaliy loyiha: "Sof Node bilan REST API (Express'siz)"

http modulini chuqur tushunish uchun — Express'siz to'liq API.

Maqsad

Faqat core http modul bilan routing, body parsing, query, status kodlar va static fayl xizmatini qo'lda amalga oshirib, Express "ichini" tushunish.

Talablar (requirements)

  1. Server: http.createServer, listen; so'rovlarni loglovchi (Misol 1).
  2. Routing: req.method + url.pathname bilan qo'lda router (Misol 2, 2.6); noma'lum yo'lga 404.
  3. REST CRUD: /tasks resursi — GET (ro'yxat), GET /tasks/:id, POST (201), PUT/PATCH, DELETE (204) (Misol 5); xotirada massiv (keyin DB — 6).
  4. Body parsing: POST/PUT body'ni stream'dan o'qib, JSON parse; o'lcham chegarasi (Misol 4, 2.8, 14).
  5. Query: /tasks?done=true&page=2 — filtr/sahifalash (Misol 3, 2.7).
  6. Status kodlar: to'g'ri kodlar (200/201/204/400/404 — 0.4).
  7. Static fayl: /public papkadan HTML/CSS stream bilan (Misol 6, 5.4).
  8. Xato boshqaruvi: noto'g'ri JSON → 400; fayl yo'q → 404; try/catch 2.13-bob.
  9. Graceful shutdown: SIGTERM'da toza yopilish (Misol 7).
  10. (Bonus) Oddiy "middleware" g'oyasi: har so'rovdan oldin ishlaydigan funksiya (log/auth) — Express middleware 5.6-bob ga tayyorgarlik.

Maslahatlar (hint)

  • req — Readable stream; body uchun data/end (5.4, 2.8).
  • req.body YO'Q — qo'lda yig'ing (Misol 4).
  • Query: new URL(req.url, ...) (2.7, 5.3).
  • res.end() har yo'lda; writeHead birinchi 2.4-bob.
  • :id uchun pathname.split("/") (Misol 5).
  • Content-Type + charset=utf-8 (6-xato).
  • DoS: body o'lchami chegarasi (Misol 4, 14).

"Tayyor" mezonlari (acceptance criteria)

  • Server ishlaydi, so'rovlarni loglaydi.
  • To'liq CRUD (GET/POST/PUT/DELETE) to'g'ri status bilan.
  • Body stream'dan o'qiladi, o'lcham cheklangan.
  • Query bilan filtr/sahifalash ishlaydi.
  • Static fayl stream bilan xizmat qilinadi.
  • Noto'g'ri JSON/fayl yo'q xatolari to'g'ri boshqarilgan.
  • Graceful shutdown ishlaydi.
  • Hech bir so'rov "osilib" qolmaydi (res.end har joyda).

Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.


10. Xulosa va keyingi bobga ko'prik

Bu bobda 0.4 nazariyasini amalga oshirib, sof http modul bilan server qurdik:

  • http.createServer(handler) — TCP server; handler har so'rovda (5.1: event loop, 5.4: EventEmitter).
  • req (IncomingMessage — Readable stream): method/url/headers; body — qo'lda stream'dan (data/end — 5.4, 2.8).
  • res (ServerResponse — Writable stream): writeHead(status, headers) → write → end (majburiy).
  • Routing qo'lda (req.method + url.pathname); query — URL 5.3-bob; status kodlar 0.4-bob.
  • Static fayl — stream + pipe 5.4-bob; graceful shutdown (production).
  • Nega Express — bularning hammasini avtomatlashtiradi (http ustida — 5.6).

Keyingi bob — 5.6-bob: Express.js — routing, middleware (chuqur), req/res, router, static fayllar. Sof httpning "og'ir"ligini his qildik; endi uni engillashtiradigan Express'ni o'rganamiz. Routing, middleware (Express'ning yuragi), req.body/req.params/req.query — hammasi avtomatik. Bu — kitobning eng amaliy va eng ko'p ishlatiladigan boblaridan biri.


Foydalanilgan rasmiy/ishonchli manbalar

  • nodejs.org/api/http — createServer, IncomingMessage, ServerResponse, writeHead, end
  • nodejs.org/learn — HTTP server yaratish
  • MDN — HTTP (0.4: metod, status, header)
Ulashish:Telegram'da

O'qiganingizni mustahkamlang

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Node.js http moduli — Express'siz server yaratish (5.5-bob) — IlmHamroh