Merhaba arkadaşlar, bugün başımı çok ağrıtan ve belki de her full-stack geliştiricinin bir kez olsun kafayı yediği bir konudan bahsedeceğim: CORS. Özellikle React veya Vue ile bir API'ye istek atarken, tarayıcıdan o meşhur “Access to fetch at ... from origin ... has been blocked by CORS policy” hatasını almayan var mı? İlk gördüğümde, “Ben sadece veri çekmek istiyorum, neden bana böyle yapıyorsun?” diye monitöre söylenmişliğim çoktur.
Yanlış Başlangıç: Frontend'deki “Geçici” Çözümler
Bu hatayı alır almaz, hepimizin ilk refleksi Google'a koşmak oluyor. Karşımıza çıkan ilk çözüm önerileri genelde frontend tarafında, tarayıcıyı “atlatan” yöntemler. Mesela, geliştirme aşamasında Chrome'u --disable-web-security flag'i ile çalıştırmak. İtiraf ediyorum, ben de acil bir demo yetiştirmem gerektiğinde bu yola başvurdum. Ama bu, yangını söndürmek yerine yangın alarmının pilini sökmek gibi bir şey. Canlı ortamda kullanıcıya “Hey, lütfen tarayıcı güvenlik ayarlarını değiştir” diyemezsiniz!
Bir diğer yaygın hata, istekleri bir proxy üzerinden geçirmek için karmaşık frontend konfigürasyonlarına girmek. Örneğin, Vue CLI veya Create React App ile gelen proxy ayarını, sadece geliştirme ortamında çalışan bir çözüm olduğunu unutup, production için de bir sihir beklemek.
Bu yöntem, geliştirme sırasında hayat kurtarıcıdır, evet. Ancak bu proxy sunucusu, build aldığınızda yok olur. Statik dosyalarınızı servis eden sunucu (Netlify, Vercel, basit bir NGINX) bu proxy kurallarını çalıştırmaz. Canlıda yine CORS duvarına toslarsınız.
CORS Nedir ve Neden Arkadaşımız Aslında?
Şimdi biraz temele inelim. CORS (Cross-Origin Resource Sharing), bir güvenlik politikasıdır. Kötü niyetli bir sitenin, sizin tarayıcınızdaki oturumunuzu kullanarak başka bir siteye (örneğin bankanıza) istek atmasını engellemek için vardır. “Same-Origin Policy”nin daha esnek halidir. Tarayıcı, sizin frontend kodunuzun farklı bir domain'e (origin) istek yapacağını görünce, önce o sunucuya “OPTIONS” türünde bir “ön istek” (preflight request) atar ve sorar: “Hey, şu origin'den biri sana istek yapmak istiyor, kabul ediyor musun?”
Eğer backend sunucusu bu OPTIONS isteğine doğru başlıklarla (headers) yanıt vermezse, tarayıcı asıl GET/POST isteğini bile yollamadan engeller. İşte kritik nokta: Bu diyaloğu sadece ve sadece backend sunucusu yönetebilir. Frontend'in bu konuda söyleyebileceği hiçbir şey yoktur.
Gerçek Çözüm: Backend'de Doğru Başlıkları Ayarlamak
İşte benim kullandığım en temiz ve kalıcı çözüm: Backend'inize gidip, gelen isteklerin origin'ine göre doğru CORS başlıklarını eklemek. Hangi teknolojiyi kullanırsanız kullanın, bunu yapmanın bir yolu mutlaka var.
Örnek olarak, Node.js (Express) backend'inde:
Laravel kullanıyorsanız, bunun için hazır bir paket var veya `cors.php` config dosyasını düzenleyebilirsiniz:
Sonuç ve Özet
Özetle, CORS bir güvenlik önlemidir ve bu önlemi devre dışı bırakma yetkisi sadece kaynağın sahibinde, yani backend sunucusundadır. Frontend'de yapılan tüm çözümler (proxy, browser flag'leri) sadece geliştirme sürecinizi kurtaran geçici bant-aid'lerdir.
Canlı ortamda sorunsuz çalışmasını istiyorsanız, backend API'nizin CORS başlıklarını, frontend uygulamanızın çalıştığı domain(ler)i açıkça belirterek yanıtlayacak şekilde yapılandırmanız şarttır.
Peki ya siz? Bu CORS hatasıyla ilk karşılaştığınızda nasıl bir çözüm bulmuştunuz? Laravel, Django, ASP.NET gibi farklı backend framework'lerinde CORS'u nasıl yapılandırıyorsunuz? Yorumlarda deneyimlerinizi paylaşın, hep birlikte öğrenelim!
Bu hatayı alır almaz, hepimizin ilk refleksi Google'a koşmak oluyor. Karşımıza çıkan ilk çözüm önerileri genelde frontend tarafında, tarayıcıyı “atlatan” yöntemler. Mesela, geliştirme aşamasında Chrome'u --disable-web-security flag'i ile çalıştırmak. İtiraf ediyorum, ben de acil bir demo yetiştirmem gerektiğinde bu yola başvurdum. Ama bu, yangını söndürmek yerine yangın alarmının pilini sökmek gibi bir şey. Canlı ortamda kullanıcıya “Hey, lütfen tarayıcı güvenlik ayarlarını değiştir” diyemezsiniz!
Bir diğer yaygın hata, istekleri bir proxy üzerinden geçirmek için karmaşık frontend konfigürasyonlarına girmek. Örneğin, Vue CLI veya Create React App ile gelen proxy ayarını, sadece geliştirme ortamında çalışan bir çözüm olduğunu unutup, production için de bir sihir beklemek.
JavaScript:
// vue.config.js veya package.json proxy ayarı (SADECE DEVELOPMENT!)
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://farkli-bir-domain.com',
changeOrigin: true,
}
}
}
}
Bu yöntem, geliştirme sırasında hayat kurtarıcıdır, evet. Ancak bu proxy sunucusu, build aldığınızda yok olur. Statik dosyalarınızı servis eden sunucu (Netlify, Vercel, basit bir NGINX) bu proxy kurallarını çalıştırmaz. Canlıda yine CORS duvarına toslarsınız.
Şimdi biraz temele inelim. CORS (Cross-Origin Resource Sharing), bir güvenlik politikasıdır. Kötü niyetli bir sitenin, sizin tarayıcınızdaki oturumunuzu kullanarak başka bir siteye (örneğin bankanıza) istek atmasını engellemek için vardır. “Same-Origin Policy”nin daha esnek halidir. Tarayıcı, sizin frontend kodunuzun farklı bir domain'e (origin) istek yapacağını görünce, önce o sunucuya “OPTIONS” türünde bir “ön istek” (preflight request) atar ve sorar: “Hey, şu origin'den biri sana istek yapmak istiyor, kabul ediyor musun?”
Eğer backend sunucusu bu OPTIONS isteğine doğru başlıklarla (headers) yanıt vermezse, tarayıcı asıl GET/POST isteğini bile yollamadan engeller. İşte kritik nokta: Bu diyaloğu sadece ve sadece backend sunucusu yönetebilir. Frontend'in bu konuda söyleyebileceği hiçbir şey yoktur.
İşte benim kullandığım en temiz ve kalıcı çözüm: Backend'inize gidip, gelen isteklerin origin'ine göre doğru CORS başlıklarını eklemek. Hangi teknolojiyi kullanırsanız kullanın, bunu yapmanın bir yolu mutlaka var.
Örnek olarak, Node.js (Express) backend'inde:
JavaScript:
const express = require('express');
const cors = require('cors'); // `npm install cors` yapın
const app = express();
// Tüm origin'lere izin vermek (Geliştirme için)
// app.use(cors());
// VEYA: Sadece belirli origin'lere izin vermek (PRODUCTION için ŞART)
const allowedOrigins = ['https://bingunluk.com', 'https://www.bingunluk.com'];
app.use(cors({
origin: function (origin, callback) {
// Postman gibi araçlardan gelen isteklerde origin `undefined` olabilir, ona izin ver.
if (!origin || allowedOrigins.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error('CORS policy ile engellendi'));
}
},
methods: ['GET', 'POST', 'PUT', 'DELETE'], // İzin verilen metodlar
allowedHeaders: ['Content-Type', 'Authorization'] // İzin verilen başlıklar
}));
// ... Route'larınız buraya gelecek
app.listen(3000, () => console.log('Sunucu 3000 portunda çalışıyor'));
Laravel kullanıyorsanız, bunun için hazır bir paket var veya `cors.php` config dosyasını düzenleyebilirsiniz:
PHP:
// config/cors.php
return [
'paths' => ['api/', 'sanctum/csrf-cookie'],
'allowed_methods' => [''],
'allowed_origins' => ['https://bingunluk.com'], // Burayı kendi domain'inizle değiştirin!
'allowed_origins_patterns' => [],
'allowed_headers' => [''],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => false,
];
Özetle, CORS bir güvenlik önlemidir ve bu önlemi devre dışı bırakma yetkisi sadece kaynağın sahibinde, yani backend sunucusundadır. Frontend'de yapılan tüm çözümler (proxy, browser flag'leri) sadece geliştirme sürecinizi kurtaran geçici bant-aid'lerdir.
Canlı ortamda sorunsuz çalışmasını istiyorsanız, backend API'nizin CORS başlıklarını, frontend uygulamanızın çalıştığı domain(ler)i açıkça belirterek yanıtlayacak şekilde yapılandırmanız şarttır.
Peki ya siz? Bu CORS hatasıyla ilk karşılaştığınızda nasıl bir çözüm bulmuştunuz? Laravel, Django, ASP.NET gibi farklı backend framework'lerinde CORS'u nasıl yapılandırıyorsunuz? Yorumlarda deneyimlerinizi paylaşın, hep birlikte öğrenelim!