13-bo‘lim
Oraliq qatlamlar (middleware)
next() qanday ishlaydi, tartibning ahamiyati, express.json, o'z qatlamingizni yozish, xato qatlami va so'rovga ma'lumot biriktirish.
Ushbu bo‘lim mundarijasi
Oraliq qatlam (middleware) - so'rov bilan javob orasida turadigan funksiya. U so'rovni ko'radi, o'zgartiradi va keyingisiga uzatadi.
Express ning deyarli hamma imkoniyati aslida oraliq qatlam.
next() zanjiri #
import express from "express";
const app = express();
const izlar = [];
app.use((sorov, javob, keyingi) => {
izlar.push("birinchi qatlam");
keyingi();
});
app.use((sorov, javob, keyingi) => {
izlar.push("ikkinchi qatlam");
keyingi();
});
app.get("/", (sorov, javob) => {
izlar.push("ishlovchi");
javob.json({ izlar });
});
const server = app.listen(0);
const port = server.address().port;
console.log(await (await fetch(`http://localhost:${port}/`)).json());
server.close();
{ izlar: [ 'birinchi qatlam', 'ikkinchi qatlam', 'ishlovchi' ] }
Har bir qatlam uch argument oladi: (sorov, javob, keyingi).
keyingi() chaqirilmasa, zanjir to'xtaydi va so'rov osilib
qoladi.
Bu eng ko'p uchraydigan xato:
app.use((sorov, javob, keyingi) => {
console.log(sorov.method);
// keyingi() UNUTILDI
});
Server xato bermaydi, jurnalda hech narsa ko'rinmaydi - so'rov shunchaki javobsiz qoladi va brauzer kutishda davom etadi.
Qoida: qatlam yo keyingi() ni chaqirsin, yo javob yuborsin.
Ikkalasini ham qilmasa - bu xato. Ikkalasini ham qilsa, bu ham
xato:
Error: Cannot set headers after they are sent to the client
Tartib hamma narsani hal qiladi #
import express from "express";
const app = express();
app.get("/erta", (s, j) => j.json({ javob: "marshrutdan" }));
app.use((sorov, javob, keyingi) => {
javob.set("X-Qatlam", "ishladi");
keyingi();
});
app.get("/kech", (s, j) => j.json({ javob: "qatlamdan keyin" }));
const server = app.listen(0);
const port = server.address().port;
const asos = `http://localhost:${port}`;
const erta = await fetch(asos + "/erta");
console.log("erta:", erta.headers.get("x-qatlam"));
const kech = await fetch(asos + "/kech");
console.log("kech:", kech.headers.get("x-qatlam"));
server.close();
erta: null
kech: ishladi
Qatlam faqat o'zidan keyin e'lon qilingan marshrutlarga ta'sir qiladi.
Shuning uchun umumiy qatlamlar - jurnal, xavfsizlik, JSON tahlili - har doim eng yuqorida turadi.
express.json #
import express from "express";
const app = express();
app.use(express.json({ limit: "100kb" }));
app.post("/talabalar", (sorov, javob) => {
javob.status(201).json({
qabul: sorov.body,
turi: typeof sorov.body,
});
});
const server = app.listen(0);
const port = server.address().port;
const javob = await fetch(`http://localhost:${port}/talabalar`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ism: "Nodira", ball: 91 }),
});
console.log(javob.status);
console.log(await javob.json());
server.close();
201
{ qabul: { ism: 'Nodira', ball: 91 }, turi: 'object' }
express.json() - 10-bo'limda qo'lda yozgan ishimizni bajaradi:
tanani yig'adi, JSON ga aylantiradi va sorov.body ga qo'yadi.
express.json() ning odatiy chegarasi - 100 KB. U yomon emas,
lekin uni ochiq yozish yaxshi odat: shunda o'quvchi chegara
borligini biladi.
Chegaradan oshgan so'rov 413 holati bilan rad etiladi - bu
10-bo'limda qo'lda yozgan himoyamiz.
Agar fayl yuklash kerak bo'lsa, express.json noto'g'ri vosita -
u faqat JSON uchun. Fayllar uchun multipart/form-data ni
tushunadigan alohida paket kerak bo'ladi.
O'z qatlamingiz #
import express from "express";
const app = express();
const jurnal = [];
function jurnalla(sorov, javob, keyingi) {
jurnal.push(`${sorov.method} ${sorov.path}`);
keyingi();
}
function faqatJson(sorov, javob, keyingi) {
if (sorov.method === "POST" && !sorov.is("application/json")) {
javob.status(415).json({ xato: "faqat JSON qabul qilinadi" });
return;
}
keyingi();
}
app.use(jurnalla);
app.use(faqatJson);
app.get("/", (s, j) => j.json({ holat: "yaxshi" }));
app.post("/", (s, j) => j.json({ holat: "qabul qilindi" }));
const server = app.listen(0);
const port = server.address().port;
const asos = `http://localhost:${port}`;
await fetch(asos + "/");
const notogri = await fetch(asos + "/", {
method: "POST",
headers: { "Content-Type": "text/plain" },
body: "oddiy matn",
});
console.log(notogri.status, await notogri.json());
console.log("jurnal:", jurnal);
server.close();
415 { xato: 'faqat JSON qabul qilinadi' }
jurnal: [ 'GET /', 'POST /' ]
sorov.is(tur) - Content-Type sarlavhasini tekshiradi. 415 -
"qo'llab-quvvatlanmaydigan format" degan holat kodi.
So'rovga ma'lumot biriktirish #
import express from "express";
const app = express();
app.use((sorov, javob, keyingi) => {
sorov.sorovId = "sinov-123";
sorov.boshlanish = 1000;
keyingi();
});
app.use((sorov, javob, keyingi) => {
javob.set("X-Sorov-Id", sorov.sorovId);
keyingi();
});
app.get("/", (sorov, javob) => {
javob.json({ id: sorov.sorovId, boshlanish: sorov.boshlanish });
});
const server = app.listen(0);
const port = server.address().port;
const javob = await fetch(`http://localhost:${port}/`);
console.log(javob.headers.get("x-sorov-id"));
console.log(await javob.json());
server.close();
sinov-123
{ id: 'sinov-123', boshlanish: 1000 }
Qatlam sorov obyektiga xossa qo'shishi mumkin va u zanjir
bo'ylab keyingi hammasiga yetib boradi.
Bu odatiy naqsh: autentifikatsiya qatlami sorov.foydalanuvchi ni
qo'yadi, marshrutlar esa undan foydalanadi (17-bo'lim).
Faqat ma'lum yo'lga #
import express from "express";
const app = express();
app.use("/admin", (sorov, javob, keyingi) => {
javob.set("X-Himoya", "bor");
keyingi();
});
app.get("/admin/panel", (s, j) => j.json({ sahifa: "panel" }));
app.get("/ochiq", (s, j) => j.json({ sahifa: "ochiq" }));
const server = app.listen(0);
const port = server.address().port;
const asos = `http://localhost:${port}`;
const admin = await fetch(asos + "/admin/panel");
console.log("admin:", admin.headers.get("x-himoya"));
const ochiq = await fetch(asos + "/ochiq");
console.log("ochiq:", ochiq.headers.get("x-himoya"));
server.close();
admin: bor
ochiq: null
app.use(yol, qatlam) - qatlamni faqat o'sha prefiks bilan
boshlanadigan yo'llarga qo'llaydi.
Xato qatlami #
import express from "express";
const app = express();
app.use(express.json());
app.get("/buzuq", async (sorov, javob) => {
throw new Error("ichki nosozlik: parol=maxfiy");
});
app.get("/notogri", (sorov, javob, keyingi) => {
const xato = new Error("id noto'g'ri");
xato.holat = 400;
keyingi(xato);
});
app.use((xato, sorov, javob, keyingi) => {
const holat = xato.holat ?? 500;
javob.status(holat).json({
xato: holat === 500 ? "ichki server xatosi" : xato.message,
});
});
const server = app.listen(0);
const port = server.address().port;
const asos = `http://localhost:${port}`;
const buzuq = await fetch(asos + "/buzuq");
console.log(buzuq.status, await buzuq.json());
const notogri = await fetch(asos + "/notogri");
console.log(notogri.status, await notogri.json());
server.close();
500 { xato: 'ichki server xatosi' }
400 { xato: "id noto'g'ri" }
Bu Express dagi eng nozik qoida:
app.use((xato, sorov, javob, keyingi) => { ... });
Express qatlamni argumentlar soni bo'yicha ajratadi. Uchta argument - oddiy qatlam, to'rtta - xato qatlami.
Agar keyingi ni yozmasangiz:
app.use((xato, sorov, javob) => { ... }); // ODDIY qatlam!
Express buni xato qatlami deb bilmaydi va u hech qachon ishlamaydi. Ishlatmasangiz ham, to'rtinchi argumentni yozing.
Yana ikki qoida:
- Xato qatlami eng oxirida turishi kerak.
- 500 xatolarida
xato.messageni mijozga bermang - yuqoridagi misolda unda parol bor edi. Jurnalga to'liq yozing, mijozga umumiy xabar bering.
Qatlam tartibi #
- Ikkita qatlam yozib, tartibini kuzating.
keyingi()ni unutib, so'rov osilishini ko'ring.- Qatlamni marshrutdan keyin qo'yib, ta'sir qilmasligini ko'ring.
express.jsonbilan tanani o'qing.limitni kichik qilib, 413 ni oling.Content-Typeni tekshiradigan qatlam yozing.sorovga xossa qo'shib, marshrutda ishlating.- Qatlamni faqat
/adminyo'liga qo'llang. - To'rt argumentli xato qatlamini yozing.
- Uchinchi argumentni olib tashlab, ishlamay qolishini ko'ring.
Xulosa #
- Oraliq qatlam -
(sorov, javob, keyingi)funksiyasi; Express ning ko'p imkoniyati shundan iborat. - Qatlam yo
keyingi()ni chaqirsin, yo javob yuborsin - ikkalasi ham bo'lmasa, so'rov osiladi. - Qatlam faqat o'zidan keyingi marshrutlarga ta'sir qiladi - umumiylarini yuqoriga qo'ying.
express.json({ limit })tanani o'qiydi va hajmni cheklaydi.- Qatlam
sorovga xossa qo'shib, uni zanjir bo'ylab uzatishi mumkin. app.use(yol, qatlam)- faqat o'sha prefiks uchun.- Xato qatlami to'rtta argument oladi va eng oxirida turadi;
keyingiishlatilmasa ham yoziladi.
Keyingi bo'limda formalar va validatsiyani o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.