Menu

Express CORS Hatası Çözümü: cors Paketiyle ve Paketsiz

CORS hatası, response sayfanın origin'ine izin vermediği için tarayıcının sayfanın API response'unu okumasını engellediği anlamına gelir. Sunucuda Access-Control-Allow-Origin göndererek ve preflight OPTIONS isteklerine cevap vererek düzeltirsin, elle ya da cors paketiyle.

Bu sayfada çalıştırılabilir editörler var. Düzenle, çalıştır ve sonucu anında gör.

CORS hatası ("No 'Access-Control-Allow-Origin' header is present"), http://localhost:5173 gibi bir origin'deki web sayfasının başka bir origin'deki API'ni çağırdığı ve response o origin'e izin verildiğini söylemediği için tarayıcının sayfanın response'u okumasına izin vermediği anlamına gelir. Çözüm sunucudadır: sayfanın origin'i ile birlikte Access-Control-Allow-Origin gönder ve tarayıcının preflight OPTIONS isteğine kabul ettiğin metot ve header'larla cevap ver. Express'te bu birkaç satırlık bir middleware ya da cors paketinden app.use(cors()) demektir.

Response ürün listesidir ve Headers sekmesinde access-control-allow-origin: https://app.example.com görünür: o origin'deki bir sayfa bunu okuyabilir. Şimdi Origin: https://app.example.com ve Access-Control-Request-Method: PUT header'larıyla OPTIONS /api/products/1 gönder. Bu, tarayıcının bir PUT öncesinde gönderdiği preflight'tır ve cevap, izin verilen metotlar ve header'larla birlikte body'siz bir 204 olur.

Tarayıcı neyi kontrol eder

Aynı origin'deki sayfaların hiçbir şeye ihtiyacı yoktur. Cross-origin bir istek için tarayıcı şu response header'larını okur:

HeaderAnlamı
Access-Control-Allow-OriginResponse'u okumasına izin verilen tek origin, ya da herkes için *
Access-Control-Allow-MethodsAsıl istekte izin verilen metotlar (yalnızca preflight)
Access-Control-Allow-HeadersSayfanın gönderebileceği istek header'ları, örneğin Authorization (yalnızca preflight)
Access-Control-Allow-CredentialsSayfa cookie gönderip cevabı okuyabiliyorsa true
Access-Control-Max-AgeTarayıcının preflight cevabını kaç saniye önbellekte tutabileceği
Vary: OriginÖnbelleklere cevabın Origin istek header'ına bağlı olduğunu söyler

Basit bir GET ya da form tarzı bir POST doğrudan sunucuya gider ve tarayıcı cevaptaki Access-Control-Allow-Origin değerini kontrol eder. Sunucu isteği yine de çalıştırır; CORS yalnızca sayfanın sonucu görüp göremeyeceğine karar verir. JSON body'li, Authorization header'lı ya da PUT veya DELETE gibi bir metotla yapılan bir istekten önce preflight OPTIONS isteği gönderilir ve asıl istek yalnızca preflight cevabı izin verirse gönderilir. Bu yüzden bir CORS middleware'i, herhangi bir route ya da auth kontrolü çalışmadan önce OPTIONS isteğine cevap vermelidir.

Birkaç origin'e credentials ile izin ver

Access-Control-Allow-Origin tek bir origin ya da * tutar, asla bir liste değil. Birkaçına izin vermek için isteğin Origin header'ını bir izin listesiyle karşılaştır ve eşleşirse geri yansıt:

İlk istekte curl'den ya da aynı origin'deki bir sayfadan gelen bir çağrı gibi Origin header'ı yoktur, bu yüzden {"origin":null} döner ve CORS header'ı gelmez. Origin: http://localhost:5173 header'ıyla GET /api/me gönder; Headers sekmesinde o origin'in geri yansıtıldığını ve access-control-allow-credentials: true değerini görürsün. Header'ı Origin: https://evil.example yap, iki CORS header'ı da kaybolur: sunucu yine cevap verir ama bir tarayıcı sayfanın onu okumasını engellerdi. Access-Control-Allow-Credentials: true sayfanın cookie göndermesine izin verir (fetch(url, { credentials: 'include' }) ile) ve tarayıcılar bunu * ile birlikte reddeder, yani credentials her zaman tam origin'i ister.

cors paketi

cors paketi aynı işi seçeneklerle yapar. npm install cors ile kur:

const cors = require('cors');

// Any origin, no cookies: fine for a public read-only API.
app.use(cors());

// Only your frontend, with cookies.
app.use(cors({
    origin: ['https://app.example.com', 'http://localhost:5173'],
    credentials: true,
    methods: ['GET', 'POST', 'PUT', 'DELETE'],
}));

// One route only.
app.get('/api/public', cors(), handler);

Seçeneksiz çağrıldığında cors(), Access-Control-Allow-Origin: * gönderir ve her preflight'a cevap verir. * değerini yalnızca giriş gerektirmeyen herkese açık veriler için kullan.

Sık yapılan hatalar

CORS'u route'lardan ya da bir auth middleware'inden sonra eklemek. Preflight OPTIONS isteği Authorization header'ı taşımaz, bu yüzden en başa konmuş bir auth kontrolü ona 401 ile cevap verir ve tarayıcı bir CORS hatası bildirir. CORS middleware'ini ilk sırada kaydet.

Credentials ile * ayarlamak. Tarayıcılar response'u reddeder. Bunun yerine belirli origin'i geri yansıt.

CORS'u frontend'de düzeltmeye çalışmak. mode: 'no-cors' gibi istek seçenekleri kısıtlamayı kaldırmaz; okuyamayacağın opak bir response verir. Bunu yalnızca sunucunun header'ları düzeltir.

app.use() ve middleware sırasının nasıl çalıştığı için Express middleware sayfasına bak.

Sıkça Sorulan Sorular

API'm Postman'de ya da curl'de çalışıyor ama tarayıcıda neden çalışmıyor?

CORS'u yalnızca tarayıcılar uygular. Postman, curl ve diğer sunucular CORS header'larını yok sayar, bu yüzden response'u her durumda okurlar. Tarayıcı ise sunucu o origin'e izin vermedikçe response'u başka bir origin'deki sayfa script'lerine vermeyi reddeder.

CORS sunucum için bir güvenlik özelliği mi?

Sunucunu değil, kullanıcıları korur. Kötü niyetli bir sayfanın kullanıcının cookie'leriyle API'nden gelen response'ları okumasını engeller. Herkes API'ni yine de bir script'ten ya da bir sunucudan çağırabilir, yani kimlik doğrulama ve yetkilendirme hâlâ senin işin.

Farklı origin ne sayılır?

Origin, şema, host ve portun birleşimidir. http://localhost:5173 ve http://localhost:3000 portları farklı olduğu için farklı origin'lerdir, https://example.com ile https://api.example.com ise host'ları farklı olduğu için.

Geliştirme sırasında CORS'tan kaçınabilir miyim?

Evet, isteği aynı origin'e çevirerek: frontend geliştirme sunucunu (örneğin Vite'ın server.proxy ayarı) /api isteklerini Express sunucusuna yönlendirecek şekilde ayarla. Böylece tarayıcı tek bir origin ile konuşur ve CORS header'larına gerek kalmaz.

Coddy programlama dilleri çizimi

Coddy ile kodlamayı öğren

Başla