Mundarija (35)
- Bu darsda
- 1. Nega bu kerak?
- 2. Proxy so'rov yo'lida
- 2.1 Bitta fayl, bitta funksiya
- 2.2 Ishlash tartibi
- 2.3 Node runtime va nom o'zgarishi
- 3. Uch javob: next, rewrite, redirect
- 3.1 Farqi
- 3.2 portfolio uchun qaysi biri?
- 4. matcher — proxy qayerda ishlaydi
- 4.1 Sintaksis
- 4.2 Biz topdik: matcher rasmni ham ushladi
- 4.3 Natija oynasida: matcher modeli
- 5. portfolio ning proxy'si
- 5.1 Kod
- 5.2 Natija oynasida: proxy qarori
- 5.3 Haqiqiy natija
- 6. Proxy'ning boshqa ishlari
- 6.1 Sarlavha va cookie
- 6.2 Til aniqlash
- 6.3 Optimistik auth — faqat birinchi qatlam
- 6.4 Tajriba: proxy va CSP nonce
- 7. Hujumchi nigohi
- 8. Portfolio qadami: noma'lum slug darhol 404
- 8.1 Fayl
- 8.2 Tekshiruv
- 9. Ko'p uchraydigan xatolar
- 10. Mashqlar
- 1-mashq (oson): qaysi javob?
- 2-mashq (o'rta): matcher modelini sinang
- 3-mashq (qiyin): ikki tilli qaror
- 4-mashq: Portfolio qadami
- 11. Real ishda
- Xulosa
- Manbalar
Next.js proxy.ts: so'rov sahifaga yetmasdan — matcher, rewrite va redirect
Qisqacha:
proxy.ts— so'rov sahifaga yoki Route Handler'ga yetmasdan oldin ishlaydigan bitta funksiya. U so'rovni boshqa sahifaga yo'naltiradi (redirect), URL'ni o'zgartirmay boshqa sahifani ko'rsatadi (rewrite), sarlavha va cookie qo'shadi. Next 16 damiddleware.tsshu nomga o'zgardi va sukut bo'yicha Node'da ishlaydi.matcher— proxy qaysi yo'llarda ishlashini belgilaydi; uni keng yozsangiz, rasm va CSS so'rovlari ham proxy'dan o'tib, buzilishi mumkin.
Bu darsda
proxy.tsso'rov yo'lida qayerda turishini va nega u "eshik oldidagi qo'riqchi" ekanini tushuntirasiz.NextResponse.next(),rewrite()varedirect()farqini haqiqiy javoblar bilan ajrata olasiz.matcheryozasiz va uning tuzog'ini ko'rasiz: kanondagi matcher.pngrasmni ham ushlagan edi.portfoliodagi Maxsus fayllar darsidan qolgan muammoni — noma'lum loyiha birinchi so'rovda 200 qaytarishini — proxy bilan tuzatasiz.- Proxy'da nima qilmaslik kerakligini bilasiz: to'liq auth tekshiruvi va sekin so'rovlar.
Oldin bilishingiz kerak: Route Handlers, Maxsus fayllar: not-found, HTTP sarlavhalari va cookie, Regex asoslari.
1. Nega bu kerak?
Maxsus fayllar darsida kanon g'alati narsani o'lchagan edi. /loyihalar/yoq2 — bunday loyiha yo'q. Sahifa notFound() chaqiradi, ekranda «Sahifa topilmadi» chiqadi. Lekin status:
yoq2 #1 200 0.181797 (birinchi so'rov: PPR qobig'i oqim bilan ketdi → 200, HTML'da <meta name="robots" content="noindex"/> va "Sahifa topilmadi")
yoq2 #2 404 0.047858 (keyingi so'rovlar: natija keshlangan → 404)
yoq2 #3 404 0.011140
yoq3 #1 200 (har yangi noma'lum slug'da birinchi so'rov yana 200)Bu natijalar/tajriba/06-notfound-status.txt dan. Har yangi noma'lum manzilning birinchi so'rovi 200 qaytaradi. Sabab: Cache Components yoqilgan loyihada sahifaning statik qobig'i darhol oqim bilan jo'natiladi — status 200 bilan. notFound() esa keyinroq, oqim ichida ishlaydi. Status allaqachon ketgan, uni qaytarib bo'lmaydi.
noindex bor, shuning uchun Google sahifani indeksga olmaydi. Lekin 200 — yolg'on javob: monitoring vositalari, havola tekshiruvchilar va boshqa dasturlar "sahifa bor" deb o'ylaydi. Oddiy yechim — dynamicParams = false — bu loyihada taqiqlangan:
# B: export const dynamicParams = false — BUILD XATO: Route segment config "dynamicParams" is not compatible with `nextConfig.cacheComponents`.Kerak bo'lgan narsa — so'rovni sahifa render bo'lishidan oldin tekshirish. Slug ro'yxatda yo'q bo'lsa, sahifani umuman boshlamaslik. Bu aynan proxy.ts ning ishi.
Hayotiy o'xshatish: bino eshigidagi qo'riqchi. U har bir kiruvchini to'xtatadi, ro'yxatga qaraydi va uch ishdan birini qiladi: o'tkazadi, boshqa eshikka yo'naltiradi yoki boshqa xonaga olib kiradi. Lekin qo'riqchi kabinetlar ichidagi ishni qilmaydi — faqat eshikda turadi.
2. Proxy so'rov yo'lida
2.1 Bitta fayl, bitta funksiya
proxy.ts loyiha ildizida yoki src/ ichida turadi (app/ bilan bir darajada). Loyihada faqat bitta proxy fayli bo'ladi. Ichida — proxy nomli funksiya va ixtiyoriy config:
import { type NextRequest, NextResponse } from "next/server";
export function proxy(request: NextRequest) {
console.log("so'rov:", request.nextUrl.pathname);
return NextResponse.next();
}
export const config = {
matcher: "/loyihalar/:slug",
};| Qism | Nima |
|---|---|
NextRequest |
Web standart Request + qulayliklar: nextUrl, cookies |
NextResponse.next() |
"o'tkazib yubor" — so'rov odatdagidek sahifaga boradi |
config.matcher |
proxy faqat shu yo'llarda ishlaydi |
NextRequest va NextResponse — Route Handlers darsidan tanish. Farqi shundaki, Route Handler javob yaratadi, proxy esa ko'pincha so'rovni yo'naltiradi.
2.2 Ishlash tartibi
Next hujjati so'rov qaysi tartibda ishlanishini aniq yozgan. Soddalashtirilgan ko'rinishi:
flowchart TB
S["Brauzer so'rovi"] --> H["next.config: headers, redirects"]
H --> P["proxy.ts"]
P --> F["Fayllar: public/, _next/static, app/"]
F --> D["Dinamik marshrut: /loyihalar/[slug]"]
D --> J["Javob"]Ikki xulosa. Birinchisi: oddiy, o'zgarmas yo'naltirish (/eski → /yangi) uchun proxy kerak emas — next.config dagi redirects undan oldin ishlaydi va soddaroq (next.config chuqur). Ikkinchisi: proxy fayllardan oldin turadi. Ya'ni matcher bo'lmasa, u har bir so'rovda ishlaydi — CSS, JS, rasm, favicon ham.
2.3 Node runtime va nom o'zgarishi
Next 15 gacha bu fayl middleware.ts deb atalardi va sukut bo'yicha Edge muhitida (cheklangan, Node API'larisiz yengil muhit) ishlardi. Node'da ishlatish imkoni 15.2 da tajriba sifatida, 15.5 da barqaror bo'lib qo'shilgan edi. Next 16 da ikki o'zgarish bo'ldi:
| Next 15 | Next 16 | |
|---|---|---|
| Fayl | middleware.ts |
proxy.ts |
| Funksiya | middleware |
proxy |
| Runtime | sukut — Edge (15.5 dan Node ham) | faqat Node; runtime sozlamasi xato beradi |
Eski middleware.ts Next 16.4 da hali ishlaydi, lekin eskirgan (deprecated): next dev va next build har safar The "middleware" file convention is deprecated. Please use "proxy" instead. deb ogohlantiradi.
Hujjat nom o'zgarishini shunday tushuntiradi: "middleware" so'zi Express'dagi middleware bilan adashtirilardi. "Proxy" esa aniqroq — ilova oldidagi tarmoq chegarasi. Hujjat yana bir narsani ochiq aytadi: bu imkoniyatni "oxirgi chora" sifatida ishlatish tavsiya etiladi.
Eski loyihani ko'chirish uchun rasmiy codemod bor (fayl va funksiya nomini almashtiradi):
npx @next/codemod@canary middleware-to-proxy .Node runtime'ning foydasi portfolio da darhol ko'rinadi: proxy fayl tizimini o'qiy oladi (node:fs/promises). Edge'da bu mumkin emas edi. Edge'ga qaytishga urinish esa xato beradi — kanon tajribasi (Runtime'lar):
Proxy does not support Edge runtimeTekshirib ko'ring: Loyihada
src/app/bor.proxy.tsni qayerga qo'yasiz:src/proxy.ts,src/app/proxy.tsyoki loyiha ildiziga?
Javob
src/proxy.ts. Qoida: proxy app/ bilan bir darajada turadi. src/ ishlatilsa — src/ ichida, aks holda — loyiha ildizida. app/ ichiga qo'yilgan proxy.ts oddiy fayl bo'lib qoladi va hech qachon ishlamaydi — xato ham bermaydi, shuning uchun bu tuzoq.
3. Uch javob: next, rewrite, redirect
3.1 Farqi
Proxy funksiyasi uchta asosiy javobdan birini qaytaradi:
| Javob | Brauzer manzili | Kim javob beradi | O'xshatish |
|---|---|---|---|
NextResponse.next() |
o'zgarmaydi | so'ralgan sahifa | qo'riqchi o'tkazdi |
NextResponse.rewrite(url) |
o'zgarmaydi | boshqa sahifa | boshqa xonaga olib kirdi |
NextResponse.redirect(url) |
o'zgaradi (307/308) | brauzer yangi so'rov yuboradi | "u eshikdan kiring" dedi |
Rewrite (qayta yozish) — foydalanuvchi /loyihalar/yoq2 ni ko'rib turadi, server esa ichkarida boshqa yo'lni chizadi. Redirect (yo'naltirish) — server "boshqa manzilga bor" deydi, brauzer manzil satri o'zgaradi va ikkinchi so'rov ketadi.
Bundan tashqari proxy javobni o'zi ham qaytara oladi: Response.json({ xato: "..." }, { status: 401 }). Bu API yo'llarida uchraydi.
3.2 portfolio uchun qaysi biri?
Noma'lum slug uchun kerak bo'lgan narsa: status 404, manzil o'zgarmasin (foydalanuvchi qaysi manzilni xato yozganini ko'rsin), sahifa — bizning chiroyli 404. Redirect /404 ga olib borsa, manzil o'zgarardi va status avval 307 bo'lardi. Demak — rewrite.
Rewrite qayerga? Kanon aqlli yo'l tanladi: mavjud bo'lmagan ichki yo'lga — /_topilmadi. Bunday sahifa yo'q, shuning uchun Next root not-found.tsx ni 404 status bilan ko'rsatadi:
return NextResponse.rewrite(new URL("/_topilmadi", request.url));_ bilan boshlangan papka nomi app/ da private papka — u hech qachon marshrut bo'lmaydi. Demak /_topilmadi ni hech kim tasodifan yaratib qo'ymaydi.
Tekshirib ko'ring: Foydalanuvchi
/loyihalar/vazifalr(xato bilan) yozdi. Proxy redirect bilan/404ga yuborsa va rewrite bilan/_topilmadini ko'rsatsa — brauzer manzil satrida nima ko'rinadi?
Javob
Redirect'da — /404: foydalanuvchi qayerda xato qilganini endi ko'rmaydi, «Orqaga» tugmasi ham chalkashadi. Rewrite'da — /loyihalar/vazifalr: manzil o'zgarmagan, xatoni ko'rib tuzatish oson. Status ham to'g'ri — 404 (redirect'da birinchi javob 307 bo'lardi).
4. matcher — proxy qayerda ishlaydi
4.1 Sintaksis
matcher — satr yoki satrlar massivi. Har satr — yo'l shabloni:
| Shablon | Mos keladi | Mos kelmaydi |
|---|---|---|
/haqimda |
/haqimda |
/haqimda-2 |
/loyihalar/:slug |
/loyihalar/bahor |
/loyihalar/bahor/rasm |
/loyihalar/:yol* |
/loyihalar, /loyihalar/a/b |
/blog |
/blog/:slug([a-z0-9-]+) |
/blog/portfolio-v2 |
/blog/rss.xml |
:slug — nomli parametr, bitta segment. * — nol yoki ko'p segment. Qavs ichida — regex: parametr qanday belgilardan iborat bo'lishi mumkin. matcher qiymatlari build vaqtida o'qiladi, shuning uchun ular o'zgarmas bo'lishi shart: o'zgaruvchidan yasalgan satrni Next e'tiborsiz qoldiradi.
matcher bo'lmasa — proxy hamma narsada ishlaydi. Hujjat ogohlantiradi: shunda auth yoki redirect mantig'i CSS, JS va rasmlarni ham to'sib qo'yishi mumkin. Shuning uchun keng tarqalgan "inkor" shabloni bor:
export const config = {
matcher: ["/((?!api|_next/static|_next/image|.*\\.png$).*)"],
};(?!...) — "bu bilan boshlanmasa" (negative lookahead). Ya'ni: api, _next/static, _next/image va .png bilan tugaydiganlardan tashqari hamma yo'l.
4.2 Biz topdik: matcher rasmni ham ushladi
Kanondagi birinchi matcher shunday edi:
export const config = {
matcher: [
"/loyihalar/:slug",
"/loyihalar/:slug/rasm",
"/blog/:slug((?!rss\\.xml$).*)",
],
};Mantiqan to'g'ri ko'rinadi: loyiha sahifasi, rasm sahifasi va blog posti (RSS'dan tashqari). O'lchovlar o'tdi, 404 tuzaldi. Lekin besh holatdan keyin, next/image darsida telefon o'lchovi g'alati natija berdi: mobil ekranda loyiha rasmi umuman ko'rinmagan.
Sabab — public/loyihalar/vazifalar.png. Uning manzili /loyihalar/vazifalar.png. :slug esa "bitta segment, istalgan belgi" degani — vazifalar.png ham bitta segment! Proxy uni loyiha slug'i deb o'yladi, ro'yxatdan topmadi va 404 ga burdi.
Biz buni Next'ning o'z sinov yordamchisi bilan tekshirdik (next/experimental/testing/server, biz ishga tushirdik, next 16.4.0):
/loyihalar/vazifalar eski: true yangi: true
/loyihalar/yoq eski: true yangi: true
/loyihalar/vazifalar/rasm eski: true yangi: true
/loyihalar/vazifalar.png eski: true yangi: false
/blog/portfolio-v2 eski: true yangi: true
/blog/rss.xml eski: false yangi: false
/ eski: false yangi: false
/haqimda eski: false yangi: falsetrue — proxy shu yo'lda ishlaydi. To'rtinchi qatorga qarang: eski matcher rasmni ushlaydi, yangisi — yo'q. Tuzatilgan matcher slug'ga qaysi belgilar ruxsatligini aytadi:
export const config = {
matcher: [
"/loyihalar/:slug([a-z0-9-]+)",
"/loyihalar/:slug([a-z0-9-]+)/rasm",
"/blog/:slug([a-z0-9-]+)",
],
};Kichik harf, raqam va chiziqcha — slug'larimiz aynan shunday. Nuqtali yo'l (.png, .xml) endi o'tmaydi, shuning uchun RSS uchun alohida istisno ham kerak emas.
Nega bu xato besh holat davomida bilinmadi? Desktop o'lchamdagi rasm variantlari eski build'lardan keshda qolgan edi. Faqat kesh tozalanib, telefon o'lchami so'ralganda xato chiqdi. Bu voqeaning to'liq tafsiloti — next/image darsida.
Maslahat: Hujjatda (16.4.0 bilan keladigan
proxy.mdham) bu yordamchining nomiunstable_doesProxyMatchdeb yozilgan. Lekin next 16.4.0 paketida faqat eski nom bor —unstable_doesMiddlewareMatch(biz paketdaginext/experimental/testing/servereksportlarini tekshirdik). Hujjat va paket farq qilsa — paket ustun: koddaunstable_doesMiddlewareMatchni yozing.unstable_prefiksi — API hali barqaror emas, nomi o'zgarishi mumkin degani.
4.3 Natija oynasida: matcher modeli
Next'ning matcher i ichkarida :slug ni regex'ga aylantiradi. G'oyani kichik model bilan ko'rsatamiz. :nom → "slash'gacha istalgan belgi", :nom(regex) → shu regex. Bu Next kodi emas — soddalashtirilgan o'quv modeli, lekin natijasi yuqoridagi haqiqiy jadval bilan bir xil:
function shablonniRegex(shablon) {
const ichi = shablon.replace(
/:(\w+)(\(([^)]*)\))?/g,
(_, nom, __, re) => `(${re ?? "[^/]+"})`,
);
return new RegExp(`^${ichi}$`);
}
const eski = shablonniRegex("/loyihalar/:slug");
const yangi = shablonniRegex("/loyihalar/:slug([a-z0-9-]+)");
const yollar = ["/loyihalar/vazifalar", "/loyihalar/vazifalar.png"];
for (const yol of yollar) {
console.log(yol, eski.test(yol), yangi.test(yol));
}
console.log(eski.source);
console.log(yangi.source);Konsolda:
/loyihalar/vazifalar true true
/loyihalar/vazifalar.png true false
^\/loyihalar\/([^/]+)$
^\/loyihalar\/([a-z0-9-]+)$[^/]+ — "slash bo'lmagan har qanday belgi, bir yoki ko'p". Nuqta ham shu to'plamga kiradi. [a-z0-9-]+ esa nuqtani o'tkazmaydi. Oxirgi ikki qator — model yasagan regex'lar (\/ — slash'ning qochirilgan ko'rinishi, ma'nosi o'sha).
5. portfolio ning proxy'si
5.1 Kod
Kanondagi src/proxy.ts (holat 27):
import { readdir } from "node:fs/promises";
import path from "node:path";
import { type NextRequest, NextResponse } from "next/server";
import { LOYIHALAR } from "@/malumot/loyihalar";
const LOYIHA_SLUGLARI = new Set(LOYIHALAR.map((l) => l.slug));
let postSluglari: Promise<Set<string>> | undefined;
function postlarniOl(): Promise<Set<string>> {
postSluglari ??= readdir(path.join(process.cwd(), "src", "blog")).then(
(f) =>
new Set(f.filter((x) => x.endsWith(".md")).map((x) => x.slice(0, -3))),
);
return postSluglari;
}
export async function proxy(request: NextRequest) {
const [, bolim, slug] = request.nextUrl.pathname.split("/");
const bormi =
bolim === "loyihalar"
? LOYIHA_SLUGLARI.has(slug ?? "")
: (await postlarniOl()).has(slug ?? "");
if (bormi) return NextResponse.next();
return NextResponse.rewrite(new URL("/_topilmadi", request.url));
}Pastida — «Biz topdik» bo'limidagi tuzatilgan config.matcher. Kanon faylidagi uzun izohlar bu yerda olib tashlandi; kod qatorlari aynan (ikkitasi 70 belgidan uzun — prettier formati).
Qatorma-qator:
| Qator | Nima qiladi |
|---|---|
LOYIHA_SLUGLARI |
loyihalar ro'yxatidan Set — tez has() tekshiruvi |
postSluglari ??= … |
blog papkasini bir marta o'qiydi, Promise'ni eslab qoladi |
split("/") |
/loyihalar/bahor/rasm → ["", "loyihalar", "bahor", "rasm"] |
bormi |
bo'lim bo'yicha tegishli to'plamdan qidiradi |
rewrite("/_topilmadi") |
yo'q bo'lsa — 404 sahifa, manzil o'zgarmaydi |
??= — "faqat bo'sh bo'lsa yoz" (mantiqiy tayinlash). Birinchi so'rov readdir ni boshlaydi, keyingilari tayyor Promise'ni oladi. Modul darajasidagi o'zgaruvchi server jarayoni yashaguncha saqlanadi. Proxy har so'rovda ishlaydi — har safar diskni o'qish sekin bo'lardi.
5.2 Natija oynasida: proxy qarori
Proxy'ning qaror qismi — toza mantiq: yo'l kiradi, qaror chiqadi. Uni Next'siz sinash mumkin (fayl o'qish o'rniga tayyor to'plam):
const LOYIHALAR = new Set(["vazifalar", "bahor", "landing"]);
const POSTLAR = new Set(["portfolio-v2", "server-components"]);
function qaror(yol) {
const [, bolim, slug] = yol.split("/");
const toplam = bolim === "loyihalar" ? LOYIHALAR : POSTLAR;
return toplam.has(slug ?? "") ? "next()" : "rewrite /_topilmadi";
}
for (const yol of [
"/loyihalar/bahor",
"/loyihalar/yoq2",
"/loyihalar/bahor/rasm",
"/blog/portfolio-v2",
"/blog/yoq",
]) {
console.log(`${yol} → ${qaror(yol)}`);
}Konsolda:
/loyihalar/bahor → next()
/loyihalar/yoq2 → rewrite /_topilmadi
/loyihalar/bahor/rasm → next()
/blog/portfolio-v2 → next()
/blog/yoq → rewrite /_topilmadi/loyihalar/bahor/rasm ham to'g'ri o'tdi: split ning uchinchi elementi baribir bahor. Bu funksiya proxy'ga faqat matcher o'tkazgan yo'llarda chaqiriladi — shuning uchun /haqimda kabi yo'llarni o'ylash shart emas.
5.3 Haqiqiy natija
Build jadvalining oxirida yangi qator paydo bo'ldi (natijalar/tekshiruv-27.txt):
ƒ Proxy (Middleware)Qavs ichidagi eski nom — Next 16.4 build chiqishi hali shunday yozadi. Sahifalar o'zgarmadi: hammasi avvalgidek ○ va ◐.
next start ustida curl bilan tekshiruv (natijalar/27-proxy-status.txt, birinchi qatorlar):
/loyihalar/yoq2 404 0.098980s <meta name="robots" content="noindex"/> Sahifa topilmadi
/loyihalar/yoq2 404 0.029150s <meta name="robots" content="noindex"/> Sahifa topilmadi
/loyihalar/yoq3/rasm 404 0.010865s <meta name="robots" content="noindex"/> Sahifa topilmadi
/blog/yoq 404 0.013855s <meta name="robots" content="noindex"/> Sahifa topilmadi
/blog/rss.xml 200 0.053749s yoq2 endi birinchi so'rovdayoq 404. Mavjud sahifalar va RSS — 200. Farq qayerdan kelganini qadamma-qadam solishtiring:
| Qadam | Proxy'siz | Proxy bilan |
|---|---|---|
1. /loyihalar/yoq2 so'rovi keldi |
sahifa render boshlanadi | proxy slug'ni to'plamdan qidiradi |
| 2. Javob boshlanadi | qobiq 200 bilan oqimda ketadi | topilmadi → rewrite /_topilmadi |
3. notFound() |
oqim ichida — status allaqachon ketgan | ishlamaydi ham: sahifa boshlanmadi |
| Natija | 200 + noindex |
404 + o'sha «Sahifa topilmadi» |
Narxi-chi? Proxy har mos so'rovda qo'shimcha kod. Kanon 6 tadan so'rov yubordi (soniyalarda, birinchisi — sovuq start):
0.037377 0.007037 0.007110 0.006864 0.009127 0.006920 ← / (proxy bilan)
0.058973 0.023385 0.014158 0.010083 0.011659 0.012055 ← /loyihalar/vazifalar (proxy bilan)
0.091689 0.010709 0.007126 0.006982 0.006199 0.006007 ← / (proxy'siz)
0.070359 0.006713 0.010841 0.010894 0.008548 0.007893 ← /loyihalar/vazifalar (proxy'siz)/loyihalar/vazifalar proxy bilan 10–23 ms, proxy'siz 7–11 ms. / — matcher'ga kirmaydi, farqi yo'q. Ya'ni bir necha millisekund — o'lchov shovqini darajasida. Lekin bu tez, chunki proxy faqat xotiradagi to'plamni tekshiradi. Ichida tarmoq so'rovi bo'lsa, har sahifa shuncha kutardi.
6. Proxy'ning boshqa ishlari
6.1 Sarlavha va cookie
Proxy so'rovga ham, javobga ham sarlavha qo'sha oladi. Cookie'lar — oddiy sarlavha (Cookie va Set-Cookie), Next ularga qulay cookies obyektini beradi. Hujjatdagi naqsh:
export function proxy(request: NextRequest) {
const tema = request.cookies.get("tema")?.value;
const sarlavhalar = new Headers(request.headers);
sarlavhalar.set("x-tema", tema ?? "tizim");
const javob = NextResponse.next({
request: { headers: sarlavhalar },
});
javob.headers.set("x-proxy", "1");
return javob;
}request: { headers } — sahifaga yetadigan so'rov sarlavhasi (sahifa uni headers() bilan o'qiydi, keyingi darsda). javob.headers — brauzerga ketadigan javob sarlavhasi. Kanonda bunday sarlavha yo'q; bu — keyingi bo'limdagi CSP tajribasining asosi.
6.2 Til aniqlash
Ko'p tilli saytda proxy /haqimda ni ichkarida /uz/haqimda ga rewrite qiladi yoki brauzer tiliga qarab /en ga yo'naltiradi. portfolio buni next-intl darsida aynan shu proxy'ga qo'shadi.
6.3 Optimistik auth — faqat birinchi qatlam
Proxy'ning eng mashhur ishi — "kirmagan foydalanuvchini /login ga yubor". Hujjat bu yerda ehtiyot bo'lishni so'raydi (tarjima): proxy optimistik tekshiruv uchun foydali, lekin u "to'liq sessiya boshqaruvi yoki avtorizatsiya yechimi sifatida ishlatilmasligi kerak".
Optimistik tekshiruv — tez, taxminiy tekshiruv: "cookie bormi?". Cookie bor bo'lsa ham u eskirgan yoki soxta bo'lishi mumkin. Haqiqiy tekshiruv (sessiya bazada bormi, foydalanuvchining huquqi yetadimi) — ma'lumotga yaqin joyda: DAL da va har Server Action ichida.
export function proxy(request: NextRequest) {
// optimistik: cookie umuman yo'q bo'lsa — darhol kirish sahifasiga
if (!request.cookies.has("sessiya")) {
return NextResponse.redirect(new URL("/kirish", request.url));
}
return NextResponse.next();
}Haqiqiy auth'ni 28-qismda quramiz. Hozir qoida yetarli: proxy — eshikdagi tez filtr, seyf qulfi emas.
6.4 Tajriba: proxy va CSP nonce
CSP nonce (bir martalik raqam) — har so'rovda yangi tasodifiy satr: brauzer faqat shu raqamli <script> larni bajaradi. Next hujjati nonce'ni aynan proxy'da yaratishni ko'rsatadi. Kanon buni sinab ko'rdi (natijalar/tajriba/27-csp.txt):
| Variant | Natija |
|---|---|
V1: 'unsafe-inline' bilan statik CSP |
0 buzilish, sahifalar statik |
V3: proxy'da nonce + 'strict-dynamic' |
0 buzilish, lekin hamma sahifa ƒ |
Nonce har so'rovda yangi — demak HTML ham har so'rovda yangi. Build'da tayyorlangan statik sahifalar yo'qoladi:
┌ ƒ /
├ ƒ /_not-found
├ ƒ /aloqa
├ ƒ /api/qayta-yangila
├ ƒ /blog 30d 1yKanon qarori — V1 (sahifalar statik qoladi). CSP'ning to'liq tahlili va boshqa variantlar (SRI, Trusted Types) — next.config chuqur darsida.
Tekshirib ko'ring: Proxy ichida har so'rovda GitHub API'ga
fetchqilib, foydalanuvchi nomini sarlavhaga qo'shmoqchisiz. Nima bo'ladi?
Javob
Har mos sahifa GitHub javobini kutadi — «Haqiqiy natija» bo'limidagi bir necha millisekund yuzlab millisekundga aylanadi. GitHub ishlamasa, butun sayt to'xtaydi. Hujjat ham ogohlantiradi: proxy sekin ma'lumot olish uchun emas, fetch ning kesh sozlamalari (next.revalidate, next.tags) proxy'da ishlamaydi. Bunday ma'lumot — keshlangan Server Component'da ("use cache").
7. Hujumchi nigohi
Proxy — eshik. Hujumchi eshikni aylanib o'tish yo'lini qidiradi:
- Matcher tirqishi. Proxy faqat
matcherdagi yo'llarda ishlaydi. Hujjat ogohlantiradi: Server Action — alohida marshrut emas, u ishlatilgan sahifaga POST. Matcher o'zgarsa yoki action boshqa sahifaga ko'chsa, proxy himoyasi jimgina yo'qoladi. Shuning uchun har action ichida o'z tekshiruvi bo'lishi shart (Server Actions xavfsizligi). - Proxy'ni chetlab o'tish. 2025-yil 21-martda Next.js'da jiddiy zaiflik e'lon qilindi (CVE-2025-29927, xavf bahosi 9.1/10 — "kritik"). Next ichida ishlatiladigan
x-middleware-subrequestsarlavhasini hujumchi o'zi qo'shib yuborsa, middleware butunlay o'tkazib yuborilardi. Auth'ni faqat middleware'da tekshirgan, o'zi xostlangan (next start,output: "standalone") saytlar ochiq qolgan; Vercel va Netlify'dagi saytlarga ta'sir qilmagan. Tuzatish — 15.2.3, 14.2.25, 13.5.9, 12.3.5 versiyalarida. Saboq doimiy: himoyaning yagona qatlami proxy bo'lmasin. - Bizning proxy'miz hech narsani yashirmaydi — u faqat 404 statusini to'g'rilaydi. Uni chetlab o'tgan odam baribir sahifaning o'z
notFound()iga uriladi. Mana shunday bo'lishi kerak: proxy — tezlik va qulaylik, xavfsizlik esa ichkarida.
8. Portfolio qadami: noma'lum slug darhol 404
8.1 Fayl
src/proxy.ts — «portfolio ning proxy'si» bo'limidagi kod va tuzatilgan matcher. Boshqa fayl o'zgarmaydi: not-found.tsx va sahifalardagi notFound() joyida qoladi (ikkinchi himoya qatlami).
Diqqat: kanon tarixida birinchi matcher
"/loyihalar/:slug"edi va.pngxatosi holat 32 da topildi. Kanon keyin holat 27 faylini ham tuzatilgan matcher bilan almashtirdi. Siz to'g'ridan tuzatilgan variantni yozing.
8.2 Tekshiruv
npm run lint
npm run tip
npm run build
npm run startBoshqa terminalda:
U=localhost:3000
curl -s -o /dev/null -w "%{http_code}\n" $U/loyihalar/yoq2
curl -s -o /dev/null -w "%{http_code}\n" $U/blog/rss.xml
curl -s -o /dev/null -w "%{http_code}\n" $U/loyihalar/vazifalar.pngKutilgan: 404, 200, 200. Kanon o'lchovi: JS o'zgarmadi (proxy serverda ishlaydi), axe 0, hydration 0.
Hali commit qilmang: kanonda bu holat (27) keyingi dars bilan birga — after() qo'shilgach — bitta commit bo'ladi.
9. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| Proxy umuman ishlamaydi, xato ham yo'q | Fayl app/ ichida yoki noto'g'ri papkada |
app/ bilan bir darajada: src/proxy.ts |
| CSS/JS/rasm yuklanmay qoldi | matcher yo'q yoki juda keng |
Inkor shabloni yoki aniq yo'llar |
Rasm 404 (/loyihalar/x.png) |
:slug nuqtali fayl nomini ham ushlaydi |
:slug([a-z0-9-]+) |
Proxy does not support Edge runtime |
config.runtime: "edge" |
Proxy faqat Node'da (Next 16) |
| Har sahifa sekinlashdi | Proxy ichida tarmoq so'rovi | Proxy'da faqat tez tekshiruv |
The "middleware" file convention is deprecated ogohlantirishi |
Eski nom — Next 16 da eskirgan (hali ishlaydi) | Codemod: middleware-to-proxy |
| Matcher o'zgaruvchidan — ta'sir qilmaydi | matcher build vaqtida statik o'qiladi |
Faqat literal satrlar |
10. Mashqlar
Mashqlar kurs/mashqlar/23/26-proxy/ da. Jonli yechimlarni «Ishga tushir» bilan sinang.
1-mashq (oson): qaysi javob?
/eski-blog→/blog, manzil satri ham o'zgarsin —- Noma'lum slug: 404 sahifa, manzil o'zgarmasin —
- Slug mavjud, hech narsa qilish shart emas —
/api/...da kalit yo'q: darhol JSON xato —
Yechim
- redirect — manzil o'zgarishi kerak. Lekin bunday o'zgarmas yo'naltirish uchun
next.configdagiredirectssoddaroq. - rewrite — ichkarida boshqa sahifa, tashqarida o'sha manzil.
- next —
NextResponse.next(): so'rov odatdagidek davom etadi. - Response —
Response.json({...}, { status: 401 }): proxy javobni o'zi qaytaradi.
2-mashq (o'rta): matcher modelini sinang
«matcher modeli» blokidagi shablonniRegex ni oling va uchta shablonni sinang: /blog/:slug, /blog/:slug([a-z0-9-]+) va /loyihalar/:slug/rasm. Yo'llar: /blog/rss.xml, /blog/salom-dunyo, /loyihalar/bahor/rasm. Har juftlik uchun shablon | yo'l | natija chiqaring. Ichma-ich for...of — har shablon uchun har yo'l.
Yechim
function shablonniRegex(shablon) {
const ichi = shablon.replace(
/:(\w+)(\(([^)]*)\))?/g,
(_, nom, __, re) => `(${re ?? "[^/]+"})`,
);
return new RegExp(`^${ichi}$`);
}
const shablonlar = [
"/blog/:slug",
"/blog/:slug([a-z0-9-]+)",
"/loyihalar/:slug/rasm",
];
const yollar = [
"/blog/rss.xml",
"/blog/salom-dunyo",
"/loyihalar/bahor/rasm",
];
for (const s of shablonlar) {
const re = shablonniRegex(s);
for (const y of yollar) {
console.log(`${s} | ${y} | ${re.test(y)}`);
}
}Konsolda:
/blog/:slug | /blog/rss.xml | true
/blog/:slug | /blog/salom-dunyo | true
/blog/:slug | /loyihalar/bahor/rasm | false
/blog/:slug([a-z0-9-]+) | /blog/rss.xml | false
/blog/:slug([a-z0-9-]+) | /blog/salom-dunyo | true
/blog/:slug([a-z0-9-]+) | /loyihalar/bahor/rasm | false
/loyihalar/:slug/rasm | /blog/rss.xml | false
/loyihalar/:slug/rasm | /blog/salom-dunyo | false
/loyihalar/:slug/rasm | /loyihalar/bahor/rasm | trueBirinchi qator — aynan kanon xatosining blog varianti: /blog/:slug RSS faylini ham ushlaydi. Kanonning birinchi matcher'i buni maxsus istisno bilan ((?!rss\.xml$)) yopgan edi, lekin .png ni unutgan. Belgilar to'plamini cheklash — ikkalasini birdaniga yopadi.
3-mashq (qiyin): ikki tilli qaror
Keyinroq portfolio ga /en prefiksi qo'shiladi: /en/loyihalar/bahor. «proxy qarori» blokidagi qaror ni shunday o'zgartiring: yo'l /en bilan boshlansa, uni olib tashlab tekshirsin, va rewrite manzili tilni saqlasin (/en/_topilmadi, o'zbekchada — /uz/_topilmadi). Kanon next-intl darsida aynan shuni regex bilan qiladi; siz startsWith va slice bilan yozing.
Yechim
const LOYIHALAR = new Set(["vazifalar", "bahor", "landing"]);
const POSTLAR = new Set(["portfolio-v2", "server-components"]);
function qaror(yol) {
const en = yol === "/en" || yol.startsWith("/en/");
const til = en ? "en" : "uz";
const ichki = en ? yol.slice(3) || "/" : yol;
const [, bolim, slug] = ichki.split("/");
const toplam = bolim === "loyihalar" ? LOYIHALAR : POSTLAR;
return toplam.has(slug ?? "")
? "next()"
: `rewrite /${til}/_topilmadi`;
}
for (const yol of [
"/loyihalar/bahor",
"/en/loyihalar/bahor",
"/en/loyihalar/yoq",
"/blog/yoq",
"/en/blog/portfolio-v2",
]) {
console.log(`${yol} → ${qaror(yol)}`);
}Konsolda:
/loyihalar/bahor → next()
/en/loyihalar/bahor → next()
/en/loyihalar/yoq → rewrite /en/_topilmadi
/blog/yoq → rewrite /uz/_topilmadi
/en/blog/portfolio-v2 → next()yol.slice(3) — /en ning uch belgisini olib tashlaydi. || "/" — faqat /en bo'lsa bo'sh satr qoladi, uni / ga aylantiramiz. Til rewrite manzilida saqlanadi — 404 sahifa ham to'g'ri tilda chiqishi uchun. Kanon buni bitta regex bilan qiladi: /^(?:\/(en|uz))?\/(loyihalar|blog)\/([a-z0-9-]+)(?:\/rasm)?$/.
4-mashq: Portfolio qadami
O'z portfolio ingizga src/proxy.ts ni qo'shing («Portfolio qadami» bo'limi). next build jadvalida ƒ Proxy (Middleware) qatori chiqishini, keyin next start ustida uchta curl natijasini tekshiring. Qo'shimcha: matcher ni ataylab eski variantga ("/loyihalar/:slug") qaytaring va /loyihalar/vazifalar.png ni so'rang — nima o'zgardi?
Yechim
Tuzatilgan matcher bilan: 404, 200, 200. Eski matcher bilan /loyihalar/vazifalar.png — 404: proxy fayl nomini slug deb o'yladi. Brauzerda loyiha sahifasini telefon o'lchamida ochsangiz, rasm o'rnida bo'sh joy qoladi (rasm optimizatori ichki so'rovi ham shu 404 ga uriladi — next/image darsida). Tekshirgach, tuzatilgan matcher'ni qaytaring. Commit'ni hali qilmang — keyingi dars bilan birga.
11. Real ishda
- Auth'li ilovalarda proxy deyarli doim bor: "cookie yo'q →
/login". Haqiqiy tekshiruv esa server kodida — bu qatlamlar (28-qism cookie va sessiyalar). - Ko'p tilli saytlarda proxy til prefiksini boshqaradi: next-intl, Paraglide kabi kutubxonalar o'z proxy funksiyasini beradi.
- A/B testlar: proxy foydalanuvchini cookie bo'yicha ikki variantdan biriga rewrite qiladi — manzil bir xil, sahifa har xil.
- Intervyu savollari: "Middleware va proxy farqi?" (nom va runtime), "rewrite va redirect farqi?", "Nega auth'ni faqat middleware'da qilish xavfli?" — CVE-2025-29927 ni bilish kuchli javob.
- Eski loyihalarda
middleware.tsvaexport const config = { runtime: "edge" }ni ko'p uchratasiz — Next 16 ga ko'chirishda codemod.
Xulosa
proxy.ts(Next 16 damiddleware.tso'rnida) — so'rov sahifaga yetmasdan ishlaydigan bitta funksiya, sukut bo'yicha Node'da.- Uch asosiy javob:
next()— o'tkaz,rewrite()— manzilni o'zgartirmay boshqa sahifa,redirect()— brauzerni boshqa manzilga yubor. matcherproxy'ni kerakli yo'llarga cheklaydi;:slugnuqtali fayl nomini ham ushlaydi — kanon.pngxatosi,[a-z0-9-]+bilan tuzatildi.portfolioda proxy noma'lum slug'ni birinchi so'rovdayoq 404 qiladi; narxi bir necha millisekund.- Proxy — optimistik filtr: sekin so'rov ham, to'liq auth ham u yerda emas; CSP nonce esa butun saytni dinamik qiladi.
Keyingi dars: Request API'lar: cookies, headers, draftMode, after — sahifa va action ichida so'rovni o'qiymiz va javobdan keyin ishlaydigan after() bilan spam loglarini yozamiz.
Manbalar
- Next.js hujjati (16.4.0,
node_modules/next/dist/docs/): "Proxy" (getting started),proxy.jsAPI reference — Matcher, Execution order, Runtime, Migration to Proxy, Unit testing; "Content Security Policy" — nextjs.org/docs/app/api-reference/file-conventions/proxy (2026-10-21 da o'qildi) - Kanon natijalari:
natijalar/tajriba/06-notfound-status.txt,natijalar/27-proxy-status.txt,natijalar/tekshiruv-27.txt,natijalar/tajriba/27-csp.txt,natijalar/tajriba/39-edge.txt; matcher xatosi —natijalar/32-rasm-oldin.txt(holat 32 da topilgan) - Matcher jadvali (
unstable_doesMiddlewareMatch) — biz ishga tushirdik, next 16.4.0, Node 24.21.0, 2026-10-21 - CVE-2025-29927 — Next.js middleware avtorizatsiyani chetlab o'tish zaifligi (2025-03-21, CVSS 9.1): github.com/vercel/next.js/security/advisories/GHSA-f82v-jwr5-mffw; Vercel postmortem (2025-03-25): vercel.com/blog/postmortem-on-next-js-middleware-bypass (ikkalasi 2026-10-21 da o'qildi)
middleware.tseskirgani — next 16.4.0proxy.md"Version history" (v16.0.0, v15.5.0, v15.2.0) va build ogohlantirishi matni (paket kodi)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!