Üdvözlet a fejlesztők világában! Valószínűleg már találkoztál vele: az a bizonyos, bosszantó hibaüzenet a böngésző konzoljában, ami arról árulkodik, hogy valami nem stimmel az API-hívásaid körül. Igen, a **CORS** hibákra gondolok. Ha **Express.js**-ben fejlesztel API-t, akkor előbb vagy utóbb szembe kell nézned ezzel a kihívással. De ne aggódj! Ez az útmutató segít neked mélységében megérteni, mi is az a CORS, miért van rá szükség, és hogyan kezelheted profi módon az Express.js API-dban.
Mi az a CORS és miért létezik?
A CORS (Cross-Origin Resource Sharing – magyarul: „Különböző Eredetű Erőforrások Megosztása”) egy biztonsági mechanizmus, amelyet a böngészők kényszerítenek ki. Célja, hogy megakadályozza azokat a rosszindulatú támadásokat, ahol egy weboldal (például egy adathalász oldal) engedély nélkül hozzáférne egy másik weboldal vagy API erőforrásaihoz.
Ennek alapja a Same-Origin Policy (Azonos Eredet Szabálya). Ez azt mondja ki, hogy egy weboldal csak akkor férhet hozzá egy másik forrás (API, másik weboldal) erőforrásaihoz, ha azok protokollja (HTTP/HTTPS), hosztneve (domain, pl. example.com) és portja megegyezik. Ha ezek közül bármelyik eltér, akkor egy „kereszt-eredetű” (cross-origin) kérésről beszélünk, amit a böngésző alapértelmezetten blokkolni fog, hacsak az API nem jelzi explicit módon, hogy engedélyezi az adott eredetből érkező kéréseket.
Képzeld el, hogy a frontend alkalmazásod a http://localhost:3000
címen fut, míg az Express.js API-d a http://localhost:5000
címen. Ez már egy kereszt-eredetű kérésnek számít, mivel a portok eltérnek. Éles környezetben ez jelentheti azt, hogy a frontend a https://app.example.com
címen, az API pedig a https://api.example.com
címen található – itt a hosztnév (aldomain) tér el.
A CORS működése a háttérben: A HTTP Fejlécek és a Preflight Kérések
Amikor egy böngésző kereszt-eredetű kérést küld, kétféle kérésről beszélhetünk:
1. Egyszerű Kérések (Simple Requests)
Ezek olyan HTTP kérések, amelyek megfelelnek bizonyos kritériumoknak:
- Metódus: `GET`, `HEAD`, `POST`
- Fejlécek: Csak bizonyos automatikusan beállított fejléceket (pl. `Accept`, `Accept-Language`, `Content-Language`) vagy a `Content-Type` fejléceket (értékei lehetnek: `application/x-www-form-urlencoded`, `multipart/form-data`, `text/plain`).
Az egyszerű kérések esetén a böngésző azonnal elküldi a kérést az API-nak. Az API válaszának tartalmaznia kell az Access-Control-Allow-Origin
fejlécet, ami jelzi a böngészőnek, hogy az adott eredet (origin) számára engedélyezett-e az erőforrás hozzáférése. Ha ez a fejléc hiányzik, vagy nem egyezik az igénylő eredetével, a böngésző blokkolja a választ.
2. Nem Egyszerű Kérések (Non-Simple Requests)
Minden olyan kérés, amely nem felel meg az egyszerű kérések kritériumainak (pl. `PUT`, `DELETE` metódusok, egyedi fejlécek mint az `Authorization`, vagy `application/json` `Content-Type`), **preflight kérést** igényel.
A **preflight kérés** egy OPTIONS metódussal elküldött kérés, amelyet a böngésző automatikusan küld az eredeti kérés elindítása előtt. Ez a kérés arra szolgál, hogy lekérdezze a szervertől, hogy milyen metódusokkal, fejlécekkel és eredetekkel engedélyezi a kommunikációt. A szervernek ekkor válaszolnia kell a megfelelő CORS fejlécekkel (pl. Access-Control-Allow-Methods
, Access-Control-Allow-Headers
, Access-Control-Allow-Origin
). Ha a szerver válasza alapján a böngésző úgy ítéli meg, hogy az eredeti kérés biztonságosan elküldhető, akkor elküldi azt. Ha nem, akkor azonnal blokkolja.
Ez a kétlépcsős folyamat biztosítja, hogy a böngésző ne küldjön potenciálisan káros kéréseket olyan szervereknek, amelyek nem támogatják a kereszt-eredetű kommunikációt, vagy nem az adott eredet számára engedélyezik azt.
CORS Fejlécek, Amikre Érdemes Figyelni
Access-Control-Allow-Origin
: Ez a legfontosabb. Meghatározza, mely eredetek (domainek) férhetnek hozzá az erőforráshoz. Értéke lehet `*` (mindenki), egy specifikus domain (pl. `https://myfrontend.com`), vagy több domain vesszővel elválasztva (bár utóbbit csak a `cors` middleware egyszerűsíti, natívan a böngésző csak egyet engedélyez).Access-Control-Allow-Methods
: Meghatározza, milyen HTTP metódusokat (pl. `GET`, `POST`, `PUT`, `DELETE`) engedélyez az API a kereszt-eredetű kérésekhez.Access-Control-Allow-Headers
: Megadja, milyen egyedi HTTP fejléceket engedélyez az API a kereszt-eredetű kérésekben (pl. `Authorization`, `X-Requested-With`).Access-Control-Allow-Credentials
: Ha a `true` értékre van állítva, az azt jelenti, hogy a böngészőnek engedélyeznie kell a hitelesítő adatok (pl. cookie-k, HTTP hitelesítési fejlécek) küldését a kereszt-eredetű kérésekkel. **Fontos:** Ha ezt `true`-ra állítod, azAccess-Control-Allow-Origin
értéke nem lehet `*`, hanem egy specifikus originnek kell lennie.Access-Control-Expose-Headers
: A böngésző alapértelmezetten csak bizonyos válaszfejléceket tesz elérhetővé a JavaScript számára. Ezzel a fejléccel extra fejléceket tehetsz elérhetővé (pl. egyedi tokenek).Access-Control-Max-Age
: Megadja, hogy a preflight kérés eredményét mennyi ideig tárolhatja a böngésző gyorsítótárában (másodpercben). Ezzel csökkenthető a preflight kérések száma.
CORS Kezelése Express.js-ben: A Gyakorlatban
Két fő módszer létezik a CORS kezelésére Express.js-ben: a manuális beállítás és a dedikált cors
middleware használata.
1. Manuális CORS Fejlécek Beállítása (Kisebb projektekhez vagy specifikus igények esetén)
Kisebb projektek vagy nagyon specifikus igények esetén beállíthatod a CORS fejléceket egyénileg, egy saját middleware-ben. Ez adja a legnagyobb kontrollt, de hibázási lehetőséget is rejthet.
const express = require('express');
const app = express();
const port = 5000;
// CORS middleware
app.use((req, res, next) => {
// Engedélyezzük az összes eredetet fejlesztési környezetben.
// Éles környezetben SPECIFIKUS origin(eke)t adjunk meg!
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
// Vagy ha több is van:
// const allowedOrigins = ['http://localhost:3000', 'https://myfrontend.com'];
// const origin = req.headers.origin;
// if (allowedOrigins.includes(origin)) {
// res.setHeader('Access-Control-Allow-Origin', origin);
// }
// Engedélyezett metódusok
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
// Engedélyezett fejlécek (pl. Authentication token)
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// Ha hitelesítő adatokkal (cookies, auth headers) küldünk kéréseket
res.setHeader('Access-Control-Allow-Credentials', true);
// Preflight kérések kezelése (OPTIONS metódus)
if (req.method === 'OPTIONS') {
res.sendStatus(200); // Vagy res.status(204).send();
} else {
next(); // Továbbengedjük a kérést a következő middleware-nek
}
});
// Példa API útvonal
app.get('/api/data', (req, res) => {
res.json({ message: 'Ez egy védett adat!' });
});
app.listen(port, () => {
console.log(`Express API fut a http://localhost:${port} címen`);
});
Ez a megközelítés működik, de könnyen hibázhatunk vele, ha nem figyelünk minden részletre, különösen a preflight kérések `OPTIONS` metódusának kezelésére.
2. A cors
Middleware Használata (Erősen Ajánlott)
A leggyakoribb és legkényelmesebb módszer az **cors
middleware** használata. Ez egy npm csomag, amely egyszerűsíti a CORS fejlécek beállítását, és automatikusan kezeli a preflight kéréseket.
Telepítés
Először is telepíteni kell a csomagot:
npm install cors
Alapvető Használat (Minden origin engedélyezése – csak fejlesztéshez!)
A legegyszerűbb, de egyben legkevésbé biztonságos módja a `cors` middleware használatának, ha minden origin számára engedélyezed a hozzáférést. **Ez éles környezetben (produkcióban) NEM ajánlott, kizárólag fejlesztéshez!**
const express = require('express');
const cors = require('cors'); // Importáljuk a cors csomagot
const app = express();
const port = 5000;
app.use(cors()); // Engedélyezi az összes eredetből érkező kérést
app.get('/api/data', (req, res) => {
res.json({ message: 'Adat mindenki számára elérhető!' });
});
app.listen(port, () => {
console.log(`Express API fut a http://localhost:${port} címen`);
});
Testreszabott CORS Konfiguráció (Ajánlott éles környezetben)
A `cors` middleware számos opcióval rendelkezik, amelyek segítségével finomhangolhatod a viselkedését, és biztonságosabbá teheted az API-dat. Ez kulcsfontosságú az **éles környezetben**.
const express = require('express');
const cors = require('cors');
const app = express();
const port = 5000;
// Kors konfiguráció
const corsOptions = {
origin: 'http://localhost:3000', // Csak ezt az egy origin-t engedélyezi
// Vagy több origin esetén egy tömböt adhatunk meg:
// origin: ['http://localhost:3000', 'https://myproductionapp.com'],
// A funkcióval dinamikusan is beállíthatjuk az origint
// origin: function (origin, callback) {
// const allowedOrigins = ['http://localhost:3000', 'https://myproductionapp.com'];
// if (allowedOrigins.includes(origin) || !origin) { // !origin a böngésző nélküli kérésekhez (pl. Postman)
// callback(null, true);
// } else {
// callback(new Error('Nem engedélyezett origin a CORS által.'));
// }
// },
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', // Engedélyezett HTTP metódusok
allowedHeaders: 'Content-Type,Authorization', // Engedélyezett fejlécek
credentials: true, // Engedélyezi a hitelesítő adatok (pl. cookie-k) küldését
optionsSuccessStatus: 200 // Preflight kérés sikerességi státusz kódja
};
app.use(cors(corsOptions)); // A konfigurált cors middleware használata
app.get('/api/data', (req, res) => {
res.json({ message: 'Védett adatok!' });
});
app.post('/api/items', (req, res) => {
// Valamilyen POST logika
res.status(201).json({ message: 'Elem létrehozva.' });
});
app.listen(port, () => {
console.log(`Express API fut a http://localhost:${port} címen`);
});
A corsOptions
főbb beállításai részletesen:
origin
:- `true`: Visszatükrözi a kérés `Origin` fejlécét (csak ha nincs `credentials: true`).
- `false`: Nem engedélyez semmilyen kereszt-eredetű kérést.
- `*`: Minden origin-t engedélyez (nem ajánlott produkcióban).
- `’https://example.com’`: Csak ezt az egy specifkus origin-t engedélyezi.
- `[‘https://example.com’, ‘https://sub.example.com’]`: Több specifkus origin-t engedélyez.
function(origin, callback) { ... }
: Egy függvény, amely dinamikusan dönti el az engedélyezést. Ideális komplex logikákhoz, pl. dinamikus domainek kezeléséhez vagy környezeti változókból való olvasáshoz.
methods
: Egy vesszővel elválasztott string vagy egy tömb, ami az engedélyezett HTTP metódusokat tartalmazza (pl. `’GET,POST’` vagy `[‘GET’, ‘POST’]`).allowedHeaders
: Egy vesszővel elválasztott string vagy egy tömb, ami az engedélyezett request fejléceket tartalmazza. Ha a kliens olyan fejléccel küld kérést, ami nincs itt, a preflight kérés hibát fog eredményezni.credentials
: Boolean érték. Ha `true`, akkor a kliens hitelesítő adatokkal (pl. cookie-k, `Authorization` fejléc) küldhet kérést. **Fontos:** Ha ez `true`, azorigin
nem lehet `*`.preflightContinue
: Boolean. Ha `true`, az `OPTIONS` preflight kéréseket átengedi a többi middleware-en is. Alapértelmezés szerint `false`, azaz a `cors` middleware kezeli az `OPTIONS` kéréseket, és válaszol, mielőtt a többi middleware-hez érnének.optionsSuccessStatus
: Szám. A preflight kérésekre adott válasz HTTP státusz kódja. Alapértelmezés szerint `204` (No Content), de gyakran látni `200` (OK) értéket is.
Környezeti Változók Használata
Éles környezetben soha ne hardcode-oljuk az **origin** értékét a kódban. Használjunk környezeti változókat (pl. `.env` fájl a `dotenv` csomaggal), hogy rugalmasabbá és biztonságosabbá tegyük az alkalmazást.
require('dotenv').config(); // `.env` fájl betöltése
const express = require('express');
const cors = require('cors');
const app = express();
const port = process.env.PORT || 5000;
const allowedOrigins = process.env.FRONTEND_URL ?
process.env.FRONTEND_URL.split(',') :
[];
const corsOptions = {
origin: (origin, callback) => {
if (!origin || allowedOrigins.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error('Nem engedélyezett origin a CORS által.'));
}
},
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
allowedHeaders: 'Content-Type,Authorization',
credentials: true,
optionsSuccessStatus: 200
};
app.use(cors(corsOptions));
// ... további útvonalak és logika
És a `.env` fájlban:
PORT=5000
FRONTEND_URL=http://localhost:3000,https://myproductionapp.com
Gyakori CORS Hibaelhárítási Tippek
Amikor CORS hibával találkozol, az alábbi lépések segíthetnek a probléma azonosításában és megoldásában:
- Böngésző Konzole: Mindig ellenőrizd a böngésző fejlesztői konzolját (általában F12, majd „Console” és „Network” fül). A konzol pontosan megmondja, melyik fejléc hiányzik, vagy mi a probléma oka.
- Request és Response Fejlécek: A „Network” fülön nézd meg a hibaüzenetet kiváltó kérés „Headers” és „Response” tabjait. Győződj meg róla, hogy az API válaszában szerepelnek a megfelelő
Access-Control-Allow-*
fejlécek, és hogy azok értékei megegyeznek a frontend által elvártakkal. - Middleware Sorrend: Az Express.js-ben a middleware-ek sorrendje számít! Győződj meg róla, hogy a `cors` middleware (vagy a manuális CORS beállítás) a legkorábbi middleware-ek között van, még az útvonalkezelők előtt.
- Preflight Kérések (`OPTIONS`): Ha nem egyszerű kérést küldesz, ellenőrizd, hogy az `OPTIONS` kérésre megfelelő választ kap-e a böngésző az API-tól. Ha a preflight kérés sikertelen, az eredeti kérés el sem indul.
- Specifikus Origin: Ha `credentials: true` van beállítva, akkor az `Access-Control-Allow-Origin` értéke nem lehet `*`. Győződj meg róla, hogy egy konkrét URL-t (vagy URL-ek listáját) adtál meg.
- Hitelesítő adatok: Ha a frontend hitelesítő adatokkal (pl. cookie-kkal, autorizációs fejlécekkel) küld kérést, győződj meg róla, hogy a `cors` konfigurációban `credentials: true` van beállítva, és a frontend is beállította az `withCredentials: true` opciót (pl. Axios-ban).
- Cache: A böngésző gyorsítótárazhatja a preflight válaszokat. Ha változtatsz a CORS beállításokon, érdemes lehet üríteni a böngésző gyorsítótárát, vagy újraindítani a böngészőt, mielőtt teszteled.
Konklúzió
A CORS elsőre bonyolultnak tűnhet, de megértve az alapvető működését és a rendelkezésre álló eszközöket, könnyedén kezelhetővé válik az **Express.js** API-ban. A **cors
middleware** a legjobb barátod ebben a folyamatban, mivel nagymértékben leegyszerűsíti a fejlécek beállítását és a preflight kérések kezelését.
Ne feledd, a **biztonság** mindig az első! Habár a fejlesztés során kényelmes lehet mindent engedélyezni (`*`), éles környezetben mindig a legszigorúbb, de még működőképes konfigurációt válaszd. Specifikáld az engedélyezett origin-eket, metódusokat és fejléceket, hogy API-d védett és robusztus maradjon a potenciális támadások ellen. A CORS nem egy ellenség, hanem egy szövetséges a webes biztonságban!
Leave a Reply