IlmHamroh
JavaScript Full-stack/16-qism. Frontend asboblari: npm, bundlerlar, config32/48-dars17 daqiqa
Mundarija (37)

Dev server proxy, HTTPS va CORS dev muhitda

Qisqacha: server.proxy dev serverga "/api bilan boshlangan so'rovni boshqa serverga uzat" deydi. Brauzer uchun API endi sahifa bilan bitta originda — CORS tekshiruvi umuman ishga tushmaydi, DevTools va terminalda hamma so'rov bir joyda. changeOrigin: true — HTTPS API'lar uchun deyarli har doim kerak. Proxy faqat dev uchun: build qilingan saytda u yo'q. Telefondan sinash — --host, HTTPS kerak bo'lsa — @vitejs/plugin-basic-ssl yoki mkcert, internetga vaqtincha ochish — tunnel va server.allowedHosts.

Bu darsda

  • Dev proxy qanday ishlashini va CORS muammosini nega yo'qotishini tushuntira olasiz.
  • server.proxy ni target, changeOrigin, rewrite, configure bilan yozasiz.
  • Proxy xatolarini (502, ECONNRESET, TLS) o'qiysiz.
  • Dev serverni HTTPS'da ishga tushirasiz va telefondan ochasiz.
  • vazifalar ning dev rejimini proxy orqali API'ga ulaysiz.

Oldin bilishingiz kerak: Vite III: env va rejimlar, CORS mijoz tomondan, Origin va Same-Origin Policy, Vite II: vite.config.

1. Nega bu kerak?

CORS mijoz tomondan darsida uchta yo'l aytgan edik: serverni sozlash, dev proxy va o'z serveringiz orqali. Ikkinchisini "Vite darsida sozlaymiz" degan edik. Origin darsida ham xuddi shu va'da bor. Vaqti keldi.

Vaziyat: dev serveringiz http://localhost:5173 da, API esa https://ilmhamroh.uz da. Bu — ikki xil origin. Brauzer har fetch da serverdan "bu saytga ruxsat bormi?" deb so'raydi. «Bahor» mashq API'si ruxsat beradi:

bash
curl -sI https://ilmhamroh.uz/api/mashq/menyu
text
Server: nginx/1.24.0 (Ubuntu)
Content-Type: application/json; charset=utf-8
Access-Control-Allow-Origin: *

(Faqat kerakli qatorlar.) Access-Control-Allow-Origin: * — "har qanday sayt". Ko'p API esa bunday emas. Masalan, 25-qismda o'zingiz yozadigan backend http://localhost:3000 da bo'ladi va siz unga CORS'ni hali sozlamagan bo'lasiz. Yoki kompaniya API'si faqat https://bahor.example.com ga ruxsat beradi — localhost ga emas. Keyin cookie bilan kirish (login) — boshqa origin'ga cookie yuborish yanada qattiq qoidalar bilan ishlaydi.

Dev proxy bularning hammasini bitta harakat bilan yechadi: brauzer API'ni o'z dev serveridan so'raydi, dev server esa so'rovni haqiqiy API'ga o'zi uzatadi. Serverlar orasida CORS yo'q — u faqat brauzer qoidasi.

Oshxona o'xshatishi: mijoz (brauzer) faqat ofitsiant bilan gaplashadi. Ofitsiant (dev server) kerak bo'lsa, buyurtmani qo'shni nonvoyxonaga o'zi olib boradi va nonni olib keladi. Mijoz uchun hammasi bitta joydan.

2. Proxy qanday ishlaydi

sequenceDiagram
  participant B as Brauzer
  participant V as Vite :5173
  participant A as ilmhamroh.uz
  B->>V: GET /api/mashq/menyu
  Note over B,V: bitta origin — CORS yo'q
  V->>A: GET /api/mashq/menyu<br/>Host: ilmhamroh.uz
  A-->>V: 200 JSON
  V-->>B: 200 JSON

Brauzer so'rovni o'z origin'iga yuboradi (/api/... — nisbiy manzil). Vite yo'lni ko'rib, uni target ga uzatadi va javobni o'zgarishsiz qaytaradi. Brauzer API'ning qayerdaligini bilmaydi ham.

2.1 Eng oddiy proxy

bahor-menyu loyihasida:

ts
import { defineConfig } from "vite";

export default defineConfig({
  server: {
    proxy: {
      "/api": {
        target: "https://ilmhamroh.uz",
        changeOrigin: true,
      },
    },
  },
});

Bu — CORS darsidagi parchaning o'zi, endi haqiqiy loyihada. Sinov (dev server ishlab turganida, ikkinchi terminalda):

bash
curl -s http://localhost:5774/api/mashq/menyu
text
[{"id":1,"nom":"Osh","narx":35000,"turkum":"taom"},{"id":2,"nom":"Lag'mon","narx":28000,"turkum":"taom"},{"id":3,"nom":"Manti","narx":30000,"turkum":"taom"},{"id":4,"nom":"Ko'k choy","narx":5000,"turkum":"ichimlik"}]

localhost dan so'radik — ilmhamroh.uz javob berdi. Javob sarlavhalarida server: nginx/1.24.0 (Ubuntu) — haqiqiy API serveri.

Kalitlar:

Kalit Nima qiladi Sukut
"/api" qaysi yo'llar uzatiladi (boshlanishi bo'yicha) — (o'zingiz yozasiz)
target qayerga: protokol, domen, port majburiy
changeOrigin Host sarlavhasini target nomiga almashtirish false
rewrite uzatishdan oldin yo'lni o'zgartirish yo'q — yo'l o'zgarmaydi
Kalit Nima qiladi Sukut
configure ichki proxy obyektiga kirish (log, sarlavhalar) yo'q
ws WebSocket ulanishlarini ham uzatish false
secure false — target'ning HTTPS sertifikatini tekshirmaslik true (tekshiradi)
cookieDomainRewrite javobdagi cookie domenini localhost ga almashtirish yo'q — domen o'zgarmaydi

Vite 8.3.3 proxy uchun ichida http-proxy-3 kutubxonasini ishlatadi (manba kodda shu nom) — kalitlar o'sha kutubxonaniki. Qisqa yozuv ham bor: "/api": "https://ilmhamroh.uz" — lekin unda changeOrigin yo'q, va bu bizni keyingi bo'limga olib keladi.

2.2 changeOrigin — nega shart

changeOrigin: false bilan sinadik. Chiqishda ikki narsaga qarang: brauzer olgan kod (502) va Vite terminalidagi Error: qatori:

text
kod: 502
19:55:32 [vite] http proxy error: /api/mashq/menyu
Error: write EPROTO 08280000:error:0A000458:SSL routines:ssl3_read_bytes:tlsv1 unrecognized name:openssl\ssl\record\rec_layer_s3.c:918:SSL alert number 112

Tarjimasi: "proxy xatosi... SSL: TLS'da tanilmagan nom". Brauzer 502 (Bad Gateway — "vositachi javob ololmadi") oldi. Nega? changeOrigin siz Vite asl so'rovdagi Host: localhost:5775 ni o'zgarishsiz yuboradi. HTTPS ulanishda server qaysi sayt so'ralayotganini shu nomdan biladi (bitta serverda ko'p sayt bo'lishi mumkin) va localhost degan saytni tanimaydi — ulanishni uzadi. changeOrigin: true nomni ilmhamroh.uz ga almashtiradi.

Qoida: tashqi HTTPS API'ga — har doim changeOrigin: true. O'z kompyuteringizdagi http://localhost:3000 ga ham zarari yo'q.

2.3 Tarmoq uzilsa

Sinov paytida bir marta ulanish kutilmaganda uzildi:

text
[vite] http proxy error: /api/mashq/menyu
Error: read ECONNRESET

ECONNRESET — "ulanishni qarshi tomon uzdi". Brauzer yana 502 oldi. Bu proxy sozlamasi xatosi emas: internet yoki API serveri vaqtincha javob bermadi. Qayta urinish — 200. Muhim saboq: 502 ni ko'rganda avval Vite terminaliga qarang — sabab o'sha yerda, brauzerda emas.

2.4 Proxy'siz: preflight so'rovi

Proxy nimadan qutqarishini aniqroq ko'raylik. Brauzer boshqa origin'ga POST va JSON (Content-Type: application/json) yubormoqchi bo'lsa, avval preflight — "oldindan so'rov" — yuboradi (CORS mijoz tomondan). Uni curl bilan takrorladik:

bash
curl -s -X OPTIONS -D - -o /dev/null \
  -H "Origin: http://localhost:5173" \
  -H "Access-Control-Request-Method: POST" \
  -H "Access-Control-Request-Headers: content-type" \
  https://ilmhamroh.uz/api/mashq/menyu
text
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS
Access-Control-Allow-Headers: Content-Type,Authorization,X-Sinov,Last-Event-ID
Access-Control-Max-Age: 600

(Faqat CORS qatorlari.) Server ruxsat berdi: hamma origin, shu metodlar, shu sarlavhalar, natijani 600 soniya eslab qolish. Bu qatorlardan biri yo'q bo'lsa — brauzer asosiy so'rovni yubormaydi ham, konsolda CORS xatosi chiqadi. Har yangi so'rov turi uchun esa — qo'shimcha aylanma yo'l (ikki so'rov o'rniga bitta).

Proxy bilan bularning hammasi yo'qoladi: /api/... — o'z origin'imiz, brauzer preflight yubormaydi, server sarlavhalari ahamiyatsiz. Lekin esda tuting: production'da proxy yo'q — u yerda server baribir to'g'ri javob berishi yoki API bitta domenda turishi kerak.

2.5 Dev serverning o'z CORS'i

Teskari savol: boshqa sayt sizning dev serveringizdan fayl so'rasa-chi? Vite 6 dan beri dev server faqat localhost va 127.0.0.1 origin'lariga CORS ruxsatini beradi (server.cors sozlamasi). Sinadik — ikkala so'rov /src/main.ts ga:

Origin sarlavhasi Javobda Access-Control-Allow-Origin
http://localhost:3000 http://localhost:3000
https://yomon.example yo'q — brauzer javobni sahifaga bermaydi

Ya'ni internetdagi begona sayt sizning brauzeringiz orqali dev serveringizdagi kodni fetch bilan o'qiy olmaydi. Bu himoyani "CORS xatosi chiqyapti" deb server.cors: true (hammasiga ruxsat) bilan o'chirmang — avval kim so'rayotganini aniqlang.

Tekshirib ko'ring: Proxy sozlandi, fetch("https://ilmhamroh.uz/api/mashq/menyu") esa baribir to'g'ridan-to'g'ri API'ga boryapti (DevTools Network'da domen — ilmhamroh.uz). Nega proxy ishlamayapti?

Javob

Proxy faqat dev serverga kelgan so'rovlarni ushlaydi. To'liq manzil (https://ilmhamroh.uz/...) bilan brauzer to'g'ridan-to'g'ri API'ga boradi — Vite bu so'rovni ko'rmaydi ham. Proxy ishlashi uchun kodda nisbiy manzil bo'lishi kerak: fetch("/api/mashq/menyu"). Production'da esa to'liq manzil kerak — shuning uchun manzil .env dan olinadi (pastda, vazifalar qadamida).

3. rewrite va configure

3.1 Yo'lni o'zgartirish

Ba'zan frontend'dagi yo'l API'dagidan farq qiladi. Masalan, kodda /bahor/menyu, API'da esa /api/mashq/menyu:

ts
"/bahor": {
  target: "https://ilmhamroh.uz",
  changeOrigin: true,
  rewrite: (path) => path.replace(/^\/bahor/, "/api/mashq"),
  configure: (proxy) => {
    proxy.on("proxyReq", (proxyReq, req) => {
      console.log("[proxy]", req.method, proxyReq.path);
    });
  },
},
  • rewrite — yo'lni oladi, yangisini qaytaradi. ^ — "boshida" (RegExp asoslari): faqat boshidagi /bahor almashadi.
  • configure(proxy) — proxy obyekti hodisalarga obuna bo'lish imkonini beradi. proxyReq — so'rov target'ga ketishidan oldin. Bu yerda — log; sarlavha qo'shish ham shu yerda (proxyReq.setHeader(...)).

curl http://localhost:5776/bahor/menyu — 200, Vite terminalida:

text
[proxy] GET /api/mashq/menyu

/bahor/yoq esa — 404: proxy ishladi, API "bunday yo'l yo'q" dedi. 404 va 502 ni farqlang: 404 — API javob berdi, 502 — javob olib bo'lmadi.

  • ws: true — WebSocket (server va brauzer orasidagi doimiy ikki tomonlama ulanish; chat, jonli buyurtmalar — backend qismlarida) ulanishlarini ham uzatish. Vite'ning o'z HMR ulanishi bilan to'qnashmasligi uchun yo'l aniq bo'lsin ("/ws").
  • Cookie domeni — API Set-Cookie: sessiya=…; Domain=bahor.example.com qaytarsa, brauzer uni localhost uchun saqlamaydi. cookieDomainRewrite: "localhost" domenni almashtiradi. Kirish (login) tizimini 28-qismda yozganda shu kerak bo'ladi.

3.3 Bir nechta backend

Katta loyihada API bitta bo'lmaydi: buyurtmalar bir serverda, to'lov boshqasida, rasmlar uchinchisida. proxy — obyekt, unda istalgancha kalit bo'lishi mumkin. Har so'rov yo'li birinchi mos kelgan kalit bo'yicha uzatiladi, shuning uchun aniqrog'ini yuqoriga yozing:

ts
proxy: {
  "/api/tolov": { target: "http://localhost:4000" },
  "/api": { target: "http://localhost:3000" },
},

/api/tolov/... — 4000-portga, qolgan /api/... — 3000-portga. Tartibni almashtirsangiz, /api hammasini "yutib" yuboradi va to'lov so'rovlari noto'g'ri serverga ketadi. Kalit ^ bilan boshlansa, u RegExp sifatida o'qiladi ("^/api/v[12]/") — murakkab holatlar uchun.

4. HTTPS dev'da

4.1 Nega dev'da HTTPS

Ko'p brauzer API'lari faqat xavfsiz kontekstda ishlaydi: Service Worker, navigator.clipboard.read, kamera, geolokatsiya (Brauzer xavfsizlik modeli). http://localhost — istisno, u xavfsiz deb hisoblanadi. Lekin telefondan http://192.168.…:5173 bilan ochsangiz — endi xavfsiz emas, Service Worker ro'yxatdan o'tmaydi. Yana bir sabab: Secure belgili cookie'lar faqat HTTPS'da yuboriladi.

4.2 Tez yo'l: @vitejs/plugin-basic-ssl

bash
npm i -D -E @vitejs/plugin-basic-ssl@2.3.0
ts
import { defineConfig } from "vite";
import basicSsl from "@vitejs/plugin-basic-ssl";

export default defineConfig({
  plugins: [basicSsl()],
});
text
  VITE v8.3.3  ready in 730 ms

  ➜  Local:   https://localhost:5778/
  ➜  Network: use --host to expose

Manzil — https. Plagin har ishga tushishda o'zi imzolagan (self-signed) sertifikat yasaydi. Uni hech kim tasdiqlamagan, shuning uchun brauzer ogohlantirish sahifasini ko'rsatadi ("Advanced → Proceed" bilan o'tasiz). curl esa umuman ulanmaydi:

text
curl: 000
exit 60
schannel: SEC_E_UNTRUSTED_ROOT (0x80090325) - The certificate chain was issued by an authority that is not trusted.

Tarjimasi: "Sertifikat zanjiri ishonchsiz tashkilot tomonidan berilgan". curl -k ("tekshirma") bilan — 200. Tez sinov uchun yetarli, har kunlik ish uchun noqulay.

4.3 To'g'ri yo'l: mkcert

mkcert — kompyuteringizda shaxsiy "sertifikat markazi" yaratadigan dastur. U markazni tizimning ishonchli ro'yxatiga qo'shadi va localhost uchun sertifikat beradi — brauzer ogohlantirmaydi. Biz uni o'rnatmadik (tizimga o'zgarish kiritadi); rasmiy hujjatdan qadamlar:

bash
mkcert -install
mkcert localhost

Ikkinchi buyruq localhost.pem va localhost-key.pem fayllarini yaratadi. Config'da:

ts
import { readFileSync } from "node:fs";

export default defineConfig({
  server: {
    https: {
      key: readFileSync("localhost-key.pem"),
      cert: readFileSync("localhost.pem"),
    },
  },
});

-key.pem — maxfiy kalit: .gitignore ga qo'shing (*.pem). mkcert -install yaratgan markazning kaliti kompyuteringizda qoladi — uni hech kimga bermang: u bilan istalgan sayt uchun "ishonchli" sertifikat yasash mumkin.

Tekshirib ko'ring: Sardor telefonda http://192.168.…:5173 ni ochdi. Sahifa chiqdi, lekin konsolda Service Worker ro'yxatdan o'tmadi. Kompyuterda (localhost) esa hammasi joyida. Nega?

Javob

Service Worker faqat xavfsiz kontekstda ishlaydi: HTTPS yoki localhost. Telefondagi manzil — oddiy http va localhost emas, shuning uchun brauzer SW'ni rad etadi. Yechim — dev serverni HTTPS'da ishga tushirish (plugin-basic-ssl yoki mkcert, mkcert'da telefonga ham markaz sertifikatini o'rnatish kerak) yoki tunnel (u https:// manzil beradi).

5. Telefondan va internetdan sinash

5.1 --host — mahalliy tarmoq

Sukut bo'yicha Vite faqat localhost da tinglaydi — telefon unga ulana olmaydi. npx vite --host (yoki server.host: true, ya'ni 0.0.0.0 — "hamma tarmoq kartalarida"):

text
  ➜  Local:   http://localhost:5765/
  ➜  Network: http://192.168.…:5765/

Manzillar va tarmoq nomlari sizning kompyuteringizga xos — biz ularni yashirdik. Vite 8 har manzil yonida tarmoq kartasining nomini ham yozadi. Telefon va kompyuter bitta Wi-Fi da bo'lsa, telefondagi brauzerda Network manzilini oching. Windows birinchi marta "Node.js'ga tarmoqqa ruxsat berilsinmi?" deb so'raydi — faqat "Private" (uy) tarmoq uchun ruxsat bering.

5.2 Tunnel — internetdan

Uzoqdagi odamga (Jasur akaga) ko'rsatish kerak bo'lsa — tunnel: kompyuteringizdagi portni vaqtincha internet manziliga ulaydigan xizmat. Mashhurlari — cloudflared (Cloudflare) va ngrok. Biz ularni ishga tushirmadik — rasmiy hujjatdagi buyruq: cloudflared tunnel --url http://localhost:5173 — u https://<tasodifiy-nom>.trycloudflare.com beradi.

Lekin Vite bunday begona nom bilan kelgan so'rovni to'sadi. Sinash uchun Host sarlavhasini qo'lda berdik:

bash
curl -s -H "Host: bahor-test.trycloudflare.com" http://localhost:5777/
text
Blocked request. This host ("bahor-test.trycloudflare.com") is not allowed.
To allow this host, add "bahor-test.trycloudflare.com" to `server.allowedHosts` in vite.config.js.

Tarjimasi: "So'rov to'sildi. Bu host'ga ruxsat yo'q. Ruxsat berish uchun uni server.allowedHosts ga qo'shing". Javob kodi — 403. Yechim:

ts
server: {
  allowedHosts: [".trycloudflare.com"],
},

Boshidagi nuqta — "shu domen va uning hamma pastki domenlari".

5.3 Production'da nima bo'ladi

Dev'dagi uchta "yordamchi" production'da boshqa narsa bilan almashadi:

Dev'da Production'da
server.proxy API serverda CORS sozlamasi yoki bitta domen (nginx, 33-qism)
plugin-basic-ssl / mkcert haqiqiy sertifikat (Let's Encrypt; GitHub Pages o'zi beradi)
--host, tunnel hosting (Pages, server)

Shuning uchun dev'dagi sozlamalar server bo'limida turadi: vite build ularni o'qimaydi ham. "Dev'da ishladi" degani "production'da ishlaydi" degani emas — deploydan oldin npm run build va npm run preview bilan tekshiring. vite preview da ham preview.proxy bor, lekin u ham faqat sizning kompyuteringizda.

6. Hujumchi nigohi

Dev server — sizning manba kodingizni beradigan server: /src/asosiy.ts, .env.development qiymatlari (import.meta.env), source map'lar. Bu kompyuteringiz ichida xavfsiz. Lekin:

  • --host kafeda. Umumiy Wi-Fi'da --host bilan ishlasangiz, tarmoqdagi istalgan odam http://<sizning-IP>:5173/src/... ni ochib, kodingizni o'qiy oladi. Ochiq tarmoqda — faqat localhost.
  • DNS rebinding. Hujumchi o'z saytida (yomon.example) skript joylaydi, keyin DNS'ni aldab, yomon.example nomini 127.0.0.1 ga yo'naltiradi. Brauzer uchun bu "o'sha sayt", aslida esa — sizning dev serveringiz; skript kodingizni o'qiydi. allowedHosts aynan shunga qarshi: begona Host nomi bilan kelgan so'rov — 403. Shuning uchun uni true (hammasiga ruxsat) qilish tavsiya etilmaydi.
  • Tunnel — vaqtincha. Tunnel manzili bor odam dev serveringizga internetdan kiradi. Ko'rsatib bo'lgach — o'chiring.
  • Proxy sirni yashirmaydi. Proxy faqat dev'da. API kaliti kerak bo'lsa, uni proxy'ning configure ida qo'shish dev'da ishlaydi, production'da esa bu kalit yana brauzerga kerak bo'lib qoladi. Sirli kalit — o'z backend'ingiz ishi.

7. Vazifalar qadami: dev proxy

Branch: chore/dev-proxy

7.1 .env.development

text
# npm run dev (development rejimi). Brauzer API'ni o'z dev serverimizdan
# so'raydi (/api/mashq/...), Vite uni API_PROXY ga uzatadi (16/#32):
# so'rovlar terminal va DevTools'da bitta origin'da, CORS yo'q
VITE_API_URL=/api/mashq
# VITE_ siz — brauzerga CHIQMAYDI, faqat vite.config.ts o'qiydi.
# O'z backend'ingiz (25-qism): .env.development.local da
# API_PROXY=http://localhost:3000
API_PROXY=https://ilmhamroh.uz

Ikki o'zgaruvchi, ikki vazifa:

  • VITE_API_URL=/api/mashq — brauzer kodi shu nisbiy manzilga so'raydi (Vite III da asosiy.ts ni import.meta.env.VITE_API_URL ga o'tkazgan edik — kod o'zgarmaydi).
  • API_PROXY — proxy qayerga uzatishi. VITE_ prefiksi yo'q: u brauzerga kerak emas. 25-qismda o'z backend'ingizni yozganda, .env.development.local ga API_PROXY=http://localhost:3000 yozasiz — kod ham, umumiy fayl ham o'zgarmaydi.

.env.production o'zgarmaydi — build'da to'liq manzil (https://ilmhamroh.uz/api/mashq).

7.2 vite.config.ts

ts
export default defineConfig(({ mode }) => {
  // "" — VITE_ siz qiymatlar ham (API_PROXY): ular faqat shu
  // faylda, brauzer kodiga faqat VITE_ bilan boshlanganlari tushadi
  const env = loadEnv(mode, process.cwd(), "");

loadEnv ning uchinchi argumenti — prefiks. Sukut — "VITE_"; "" — "hammasi". Busiz env.API_PROXY — undefined bo'lardi. Brauzer kodiga baribir faqat VITE_ o'zgaruvchilar tushadi — bu Vite'ning o'z qoidasi, loadEnv ga bog'liq emas.

return { … } ichida, base dan keyin:

ts
    server: {
      // Dev proxy (16/#32): /api/... → API_PROXY
      // (.env.development).
      // changeOrigin — Host sarlavhasi API_PROXY nomiga almashadi
      proxy: env.API_PROXY
        ? { "/api": { target: env.API_PROXY, changeOrigin: true } }
        : {},
    },

API_PROXY yo'q bo'lsa (production rejimi) — bo'sh obyekt, proxy yo'q. (Bu {} ni tsconfig: app/node darsida tsc tekshiradi va undefined ga almashtiramiz — hozircha ishlaydi.)

7.3 Tekshirish

npm run dev va brauzer tekshiruvi (dev rejimda):

text
  VITE v8.3.3  ready in 470 ms
…
  200 /api/mashq/vazifalar/e9ad4eb6-f491-4b80-be4c-c8a9cd03b0d1
  200 /api/mashq/vazifalar/e9ad4eb6-f491-4b80-be4c-c8a9cd03b0d1

So'rovlar endi localhost ga, ikkalasi — 200. Modul ichida (curl bilan /src/asosiy.ts):

text
import.meta.env = {"BASE_URL": "/", "DEV": true, "MODE": "development", "PROD": false, "SSR": false, "VITE_API_URL": "/api/mashq"}

API_PROXY so'zi modulda — 0 marta: brauzerga chiqmadi. CSP buzilishi — 0: connect-src 'self' endi API so'rovlarini ham qamraydi (bitta origin). Production build o'zgarmadi — hash o'sha Dvsf2Sj6.

Halol eslatma: bizning API'da Access-Control-Allow-Origin: * bor, shuning uchun vazifalar ga proxy CORS uchun shart emas edi. Foydasi boshqa: bitta origin (DevTools'da hamma so'rov bir xil domenda), va 25-qismda o'z backend'ingizga bitta qator bilan o'tish.

bash
git switch -c chore/dev-proxy
git add .
git commit -m \
"chore: dev proxy — /api so'rovlari API_PROXY ga (.env.development)"

Diff: 2 fayl, +18 −3. Testlar 146/146, brauzer tekshiruvi 159/159.

8. Ko'p uchraydigan xatolar

8.1 Proxy production'da ishlaydi deb o'ylash

vite build natijasida proxy yo'q — dist/ statik fayllar. Production'da API yoki CORS'ni sozlaydi, yoki frontend va API bitta domenda turadi (nginx proxy — 33-qismda).

8.2 changeOrigin siz HTTPS target

502 va tlsv1 unrecognized name — changeOrigin: true qo'shing.

8.3 Proxy kaliti juda keng

"/a": {...} — /assets/... ham /a bilan boshlanadi va API'ga ketib qoladi. Kalit aniq bo'lsin: "/api/".

8.4 .env o'zgardi, proxy eskicha

API_PROXY ni o'zgartirsangiz — Vite qayta ishga tushadi (Vite III), lekin terminalda restarting server qatorini kuting.

9. Mashqlar

Mashqlar kurs/mashqlar/16/32-proxy/ da — bahor-menyu nusxasi. Mashq API'si: https://ilmhamroh.uz/api/mashq/menyu (daqiqasiga 120 so'rovgacha).

1-mashq (oson): Proxy'dan o'tadimi?

Config: proxy: { "/api": { target: "https://ilmhamroh.uz", changeOrigin: true } }. Qaysi so'rov API'ga uzatiladi?

  1. fetch("/api/mashq/menyu") —
  2. fetch("https://ilmhamroh.uz/api/mashq/menyu") —
  3. <img src="/assets/osh.png"> —
  4. npm run build dan keyin fetch("/api/mashq/menyu") —
Yechim
  1. Ha — nisbiy manzil, /api bilan boshlanadi.
  2. Yo'q — to'liq manzil, brauzer to'g'ridan-to'g'ri boradi.
  3. Yo'q — /assets /api bilan boshlanmaydi.
  4. Yo'q — build'da dev server yo'q; so'rov saytning o'z serveriga ketadi (Pages'da — 404).

2-mashq (o'rta): Menyu API'dan

  1. .env.development: VITE_API_URL=/api/mashq, API_PROXY=https://ilmhamroh.uz; .env.production: VITE_API_URL=https://ilmhamroh.uz/api/mashq.
  2. vite.config.ts — funksiya ko'rinishi, loadEnv(mode, process.cwd(), ""), API_PROXY bo'lsa /api proxy.
  3. main.ts — ${VITE_API_URL}/menyu dan taomlarni olib, <ul> ga chiqarsin (nom va narx).
  4. Tekshiring: dev'da curl localhost:<port>/api/mashq/menyu — 200; build ichida to'liq manzil.
Yechim

src/main.ts:

ts
// 2-mashq: menyu API'dan (dev'da — proxy orqali)
import "./style.css";
import { formatPrice } from "./menyu.ts";

interface ApiDish {
  id: number;
  nom: string;
  narx: number;
}

const list = document.querySelector<HTMLUListElement>("#menyu")!;
const response = await fetch(`${import.meta.env.VITE_API_URL}/menyu`);
const dishes = (await response.json()) as ApiDish[];
for (const dish of dishes) {
  const item = document.createElement("li");
  item.textContent = `${dish.nom} — ${formatPrice(dish.narx)}`;
  list.append(item);
}

Top-level await — modul skriptda ishlaydi. as ApiDish[] — json() any qaytaradi; haqiqiy loyihada javobni tekshirish kerak (API ma'lumotlarini tiplash). Natija: tsc toza; build ichida https://ilmhamroh.uz/api/mashq/menyu; dev'da modul "VITE_API_URL": "/api/mashq" ni ko'radi va /api/mashq/menyu — 200.

3-mashq (qiyin): rewrite, log va tunnel

Config'ga qo'shing: (1) /bahor/... → /api/mashq/... (rewrite), har uzatilgan so'rov terminalga yozilsin; (2) *.trycloudflare.com manzillariga ruxsat. Tekshiring: curl localhost:<port>/bahor/menyu — 200 va terminalda [proxy] GET /api/mashq/menyu; curl -H "Host: bahor-test.trycloudflare.com" … — 200, -H "Host: begona.example.com" — 403.

Yechim
ts
// vite.config.ts — 2–3-mashq: dev proxy
import { defineConfig, loadEnv } from "vite";

// 3-mashq: /bahor/menyu → /api/mashq/menyu
const toApi = (path: string) =>
  path.replace(/^\/bahor/, "/api/mashq");

export default defineConfig(({ mode }) => {
  // "" — VITE_ siz API_PROXY ham kerak (u brauzerga chiqmaydi)
  const env = loadEnv(mode, process.cwd(), "");
  const target = env.API_PROXY;
  return {
    server: {
      proxy: target
        ? {
            "/api": { target, changeOrigin: true },
            "/bahor": {
              target,
              changeOrigin: true,
              rewrite: toApi,
              configure: (proxy) => {
                proxy.on("proxyReq", (proxyReq, req) => {
                  console.log("[proxy]", req.method, proxyReq.path);
                });
              },
            },
          }
        : undefined,
      // 3-mashq: tunnel manzili (cloudflared) — ruxsat
      allowedHosts: [".trycloudflare.com"],
    },
  };
});

Natija (bizda): /api/mashq/menyu: 200, /bahor/menyu: 200, tunnel host: 200, begona host: 403, terminalda [proxy] GET /api/mashq/menyu. { target, changeOrigin: true } — qisqa yozuv: target: target (Obyekt: kalit-qiymat juftliklari dagi qisqa yozuv).

10. Real ishda

  • Deyarli har frontend jamoasida server.proxy bor: frontend dasturchi backend'ni lokal ishga tushiradi yoki staging API'ga proxy qiladi. Cookie bilan kirish (sessiya) ayniqsa proxy bilan qulay — bitta origin.
  • Telefondan sinash — mobil-birinchi saytlarda kundalik ish: --host + bitta Wi-Fi.
  • Intervyu savollari: "CORS xatosini frontend'da qanday tuzatasiz?" (to'g'ri javob: frontend'da tuzatib bo'lmaydi; dev'da — proxy, production'da — server sozlamasi), "changeOrigin nima qiladi?", "Proxy production'da ishlaydimi?".

Xulosa

  • Dev proxy brauzer so'rovini dev serverdan haqiqiy API'ga uzatadi: bitta origin, CORS tekshiruvi yo'q. Faqat dev'da.
  • target + changeOrigin: true (HTTPS uchun shart: aks holda tlsv1 unrecognized name, 502); rewrite — yo'l, configure — log va sarlavhalar, ws, cookieDomainRewrite.
  • 502 — javob olinmadi (sababi Vite terminalida), 404 — API javob berdi.
  • HTTPS: plugin-basic-ssl (tez, ogohlantirish bilan) yoki mkcert (ishonchli). Telefon — --host, internet — tunnel + allowedHosts.
  • vazifalar: dev'da VITE_API_URL=/api/mashq, API_PROXY (VITE_ siz, loadEnv(..., "")); production build o'zgarmadi.

Keyingi dars: webpack konseptlari: legacy loyihani o'qish — ko'p kompaniyalarda hali ishlayotgan webpack config'ini Vite bilimingiz orqali o'qiymiz.

Manbalar

  • Vite hujjatlari: "Server Options" — server.proxy, server.host, server.https, server.allowedHosts — vite.dev/config/server-options
  • @vitejs/plugin-basic-ssl 2.3.0 — github.com/vitejs/vite-plugin-basic-ssl
  • mkcert — github.com/FiloSottile/mkcert; Cloudflare Tunnel — developers.cloudflare.com/cloudflare-one/connections/connect-networks/
  • Vite xavfsizlik e'loni (2025-01): server.allowedHosts va DNS rebinding — github.com/vitejs/vite/security/advisories
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Dev server proxy, HTTPS va CORS dev muhitda — IlmHamroh