Merhaba arkadaşlar, bugün başımı çok ağrıtan bir sorunu ve bulduğum çözümü paylaşmak istiyorum. API'mi birden fazla domain'den (örneğin, farklı müşteri sitelerinden) çağırmam gerekiyordu ve her yeni domain için sunucuyu restart etmek, CORS whitelist'ini güncellemek can sıkıcı bir hal almıştı. "Bu işin daha dinamik bir yolu olmalı" diye düşünüp kolları sıvadım.
Karşılaştığım Sorun
Klasik Express.js CORS yapılandırması genelde şöyle oluyor:
Her yeni müşteri domain'i eklediğimde bu listeyi güncellemem ve uygulamayı yeniden başlatmam gerekiyordu. Bu, hem geliştirme sürecini yavaşlatıyor hem de canlı sistemde downtime'a sebep oluyordu. Ayrıca, origin kontrolünü daha esnek, mesela bir veritabanı sorgusu veya pattern eşleştirme ile yapmak istiyordum.
Dinamik Origin Validasyonu Fikri
Çözüm olarak, `cors` paketinin `origin` seçeneğine sadece bir dizi değil, bir fonksiyon da verebileceğimi fark ettim. Bu fonksiyon, gelen isteğin `origin` header'ını alıp, bu origin'e izin verilip verilmeyeceğine dair bir boolean (true/false) veya callback döndürebiliyor. İşte benim kullandığım en temiz çözüm:
Pattern'imi Bir Veritabanı İle Güçlendirmek
Ancak benim asıl ihtiyacım, izin verilen domain'leri bir veritabanında (örneğin, müşteri kayıtlarında) tutmaktı. İşte o zaman bu pattern'i bir adım öteye taşıdım. Fonksiyonu, veritabanından gelen dinamik bir liste ile çalışacak hale getirdim.
Bu yapı sayesinde, yeni bir müşteri kaydolduğunda veya mevcut bir müşteri için API erişimini açtığımda, sadece veritabanındaki `apiIzinli` alanını güncellemem yeterli oluyor. Bir sonraki istekte CORS middleware'imiz bu değişikliği otomatik olarak uyguluyor. Canlı sistemi restart etmeye gerek kalmıyor!
Siz backend geliştirirken CORS yönetimi için nasıl bir yol izliyorsunuz? Özellikle mikroservis veya multi-tenant mimarilerde benzer bir sorunla karşılaştınız mı? Veritabanı sorgusunu performans için nasıl cache'lersiniz? Yorumlarda deneyimlerinizi paylaşın!
Klasik Express.js CORS yapılandırması genelde şöyle oluyor:
JavaScript:
const cors = require('cors');
app.use(cors({
origin: ['https://musteri1.com', 'https://musteri2.com'] // Sabit liste
}));
Çözüm olarak, `cors` paketinin `origin` seçeneğine sadece bir dizi değil, bir fonksiyon da verebileceğimi fark ettim. Bu fonksiyon, gelen isteğin `origin` header'ını alıp, bu origin'e izin verilip verilmeyeceğine dair bir boolean (true/false) veya callback döndürebiliyor. İşte benim kullandığım en temiz çözüm:
JavaScript:
const cors = require('cors');
const allowedOriginPatterns = [
/^https:\/\/musteri-\d+\.firma\.com$/, // musteri-1.firma.com, musteri-2.firma.com gibi
/^https:\/\/staging\.(.)\.projem\.com$/, // staging alt domain'leri
'https://kesin-izinli-domain.com' // Tekil domain
];
// Dinamik kontrol fonksiyonu
const corsOptionsDelegate = function (req, callback) {
const requestOrigin = req.header('Origin');
let corsOptions;
// Eğer origin yoksa (örneğin aynı origin'den istek) veya pattern'lerden biri ile eşleşiyorsa izin ver
if (!requestOrigin || allowedOriginPatterns.some(pattern => {
if (typeof pattern === 'string') {
return pattern === requestOrigin;
} else if (pattern instanceof RegExp) {
return pattern.test(requestOrigin);
}
return false;
})) {
corsOptions = { origin: true }; // İstek origin'ine izin ver
} else {
corsOptions = { origin: false }; // İzni reddet
}
callback(null, corsOptions);
};
app.use(cors(corsOptionsDelegate));
Ancak benim asıl ihtiyacım, izin verilen domain'leri bir veritabanında (örneğin, müşteri kayıtlarında) tutmaktı. İşte o zaman bu pattern'i bir adım öteye taşıdım. Fonksiyonu, veritabanından gelen dinamik bir liste ile çalışacak hale getirdim.
JavaScript:
const corsOptionsDelegate = async function (req, callback) {
const requestOrigin = req.header('Origin');
let corsOptions;
if (!requestOrigin) {
// Origin yoksa, belki same-origin isteği veya bir API tool'u. Dikkatli ol!
return callback(null, { origin: false }); // Veya güvenli bir şekilde true da yapılabilir.
}
try {
// Veritabanından izinli domain listesini çek (cache'leyebilirsin!)
const allowedDomains = await MusteriModel.find({ apiIzinli: true }, 'domain').lean();
const domainList = allowedDomains.map(m => m.domain);
// Gelen origin, listemizde var mı?
if (domainList.includes(requestOrigin)) {
corsOptions = { origin: true };
} else {
corsOptions = { origin: false };
// İstersen log atabilirsin: console.warn(`CORS Reddedildi: ${requestOrigin}`);
}
} catch (error) {
// DB hatasında güvenli tarafta kal, izin verme.
console.error('CORS DB Hatası:', error);
corsOptions = { origin: false };
}
callback(null, corsOptions);
};
// Middleware'i async fonksiyonla kullanmak için
app.use((req, res, next) => {
cors(corsOptionsDelegate)(req, res, next);
});
Bu yapı sayesinde, yeni bir müşteri kaydolduğunda veya mevcut bir müşteri için API erişimini açtığımda, sadece veritabanındaki `apiIzinli` alanını güncellemem yeterli oluyor. Bir sonraki istekte CORS middleware'imiz bu değişikliği otomatik olarak uyguluyor. Canlı sistemi restart etmeye gerek kalmıyor!
Siz backend geliştirirken CORS yönetimi için nasıl bir yol izliyorsunuz? Özellikle mikroservis veya multi-tenant mimarilerde benzer bir sorunla karşılaştınız mı? Veritabanı sorgusunu performans için nasıl cache'lersiniz? Yorumlarda deneyimlerinizi paylaşın!