- Konu sahibi
- #1
CORS, tarayıcıdaki JavaScript’in farklı bir origin’den gelen yanıtı okuyabilmesi için sunucunun izin verdiği paylaşımı HTTP başlıklarıyla bildiren mekanizmadır. Açılımı Cross-Origin Resource Sharing şeklindedir. Örneğin arayüzünüz
CORS, sunucunun isteği mutlaka kabul etmesini sağlamaz; sunucunun verdiği yanıtın tarayıcıdaki JavaScript koduna okunabilir olup olmayacağını kontrol eder. Sorun; sunucu başlıkları, başarısız preflight veya istemcinin kimlik bilgisi seçeneğiyle sunucu politikasının uyuşmaması gibi nedenlerle ortaya çıkabilir.
Tarayıcı isteği gönderirken kaynağı
Basit bir istek için örnek yanıt başlığı şöyledir:
İstek PUT/DELETE gibi bir yöntem, application/json gibi güvenli liste dışında bir içerik türü veya
Örneğin frontend şu isteği gönderiyor olsun:
API sunucusu
İzin politikasını ihtiyaca göre dar tutmak gerekir. Aşağıdaki karar tablosu uygun başlık seçimini kolaylaştırır.
Örneğin izin verilen arayüzle birlikte çapraz kaynak çerez erişimi gerçekten gerekiyorsa sunucu yanıtı şu başlıkları kullanabilir:
Çapraz kaynak çerez isteğinde istemcide credentials: "include" gerekir; çerezin SameSite politikası gibi koşullar yine geçerlidir. Dinamik olarak izin verilen Origin yanıtı seçiliyorsa önbelleğin yanıtları karıştırmaması için Vary: Origin kullanılmalıdır. Kimlik bilgileri kullanılmıyorsa
CORS'u frontend kodunda
Bir diğer hata, istekte gönderilen
Postman, tarayıcının same-origin ve CORS kurallarına tabi değildir. Bu nedenle Postman'da başarılı olan isteğin tarayıcıda da çalışması için API yanıtlarının uygun CORS başlıklarını içermesi gerekir.
Hayır. Protokol veya port farklılığı da origin'i değiştirir. Örneğin
https://app.example.com adresinden çalışırken API'niz https://api.example.com adresindeyse tarayıcı bu isteği çapraz kaynak isteği olarak değerlendirir. API sunucusu uygun CORS yanıt başlıklarını göndermiyorsa istek tarayıcı tarafından engellenebilir.CORS, sunucunun isteği mutlaka kabul etmesini sağlamaz; sunucunun verdiği yanıtın tarayıcıdaki JavaScript koduna okunabilir olup olmayacağını kontrol eder. Sorun; sunucu başlıkları, başarısız preflight veya istemcinin kimlik bilgisi seçeneğiyle sunucu politikasının uyuşmaması gibi nedenlerle ortaya çıkabilir.
CORS nasıl çalışır?
Tarayıcı isteği gönderirken kaynağı
Origin başlığıyla bildirir. Sunucu da izin verilen kaynağı Access-Control-Allow-Origin başlığıyla belirtir.Basit bir istek için örnek yanıt başlığı şöyledir:
Kod:
Access-Control-Allow-Origin: https://app.example.com
İstek PUT/DELETE gibi bir yöntem, application/json gibi güvenli liste dışında bir içerik türü veya
Authorization gibi belirli başlıklar içeriyorsa tarayıcı önce preflight adı verilen bir OPTIONS isteği gönderir. Sunucu bu isteğe izin verilen yöntem ve başlıkları bildirerek cevap vermelidir.
Kod:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Örneğin frontend şu isteği gönderiyor olsun:
Kod:
fetch('https://api.example.com/profile', {
headers: {
'Authorization': 'Bearer token'
}
});
API sunucusu
Authorization başlığına izin vermiyorsa tarayıcı gerçek isteği göndermeden önce CORS hatası üretebilir.Hangi ayarı kullanmalıyım?
İzin politikasını ihtiyaca göre dar tutmak gerekir. Aşağıdaki karar tablosu uygun başlık seçimini kolaylaştırır.
| İhtiyaç | Önerilen ayar | Dikkat edilmesi gereken |
|---|---|---|
| Herkese açık, kimlik doğrulamasız API | Access-Control-Allow-Origin: * | Kimlik bilgileriyle birlikte kullanılmamalı |
| Belirli frontend adresi | Origin değerini açıkça belirtin | Şema, alan adı ve port tam eşleşmeli |
| Çerez veya kimlik bilgisi gönderimi | Access-Control-Allow-Credentials: true | Allow-Origin için * kullanılamaz |
| PUT, DELETE veya özel başlıklar | OPTIONS yanıtını yapılandırın | Yöntem ve başlık izinlerini ayrıca belirtin |
Kod:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true
Çapraz kaynak çerez isteğinde istemcide credentials: "include" gerekir; çerezin SameSite politikası gibi koşullar yine geçerlidir. Dinamik olarak izin verilen Origin yanıtı seçiliyorsa önbelleğin yanıtları karıştırmaması için Vary: Origin kullanılmalıdır. Kimlik bilgileri kullanılmıyorsa
Access-Control-Allow-Credentials eklemeyin. * değerini tüm API'lerde varsayılan çözüm olarak kullanmak, API yanıtlarının gereğinden fazla kaynağa açılmasına yol açabilir.CORS hatasını düzeltme adımları
- Tarayıcı geliştirici araçlarında isteğin gerçek URL'sini,
Origindeğerini ve dönen yanıt başlıklarını kontrol edin. - API'nin normal yanıtında
Access-Control-Allow-Originbaşlığının bulunduğunu doğrulayın. - İstek preflight oluşturuyorsa
OPTIONSyanıtının başarılı döndüğünü kontrol edin. - Kullandığınız HTTP yöntemi ve özel başlıklar için
Access-Control-Allow-MethodsileAccess-Control-Allow-Headersdeğerlerini ekleyin. - Çerez veya oturum bilgisi kullanıyorsanız istemci tarafında kimlik bilgisi seçeneğini ve sunucudaki
Allow-Credentialsayarını birlikte yapılandırın. - Değişiklikten sonra isteği yeniden deneyin; proxy, CDN veya önbellek kullanıyorsanız
Originbaşlığına göre yanıtların ayrıştırıldığını da kontrol edin.
Sık yapılan hatalar
CORS'u frontend kodunda
mode: 'no-cors' yazarak çözmeye çalışmak genellikle işe yaramaz. Bu modda yanıt çoğunlukla opak olur; JavaScript yanıt gövdesini ve başlıklarını okuyamaz. Sorun API sunucusundaysa çözüm sunucu veya aradaki proxy yapılandırmasında yapılmalıdır.Bir diğer hata, istekte gönderilen
Origin değerini kontrol etmeden her kaynağı geri yansıtmaktır. Özellikle çerez ve oturum bilgileri söz konusuysa yalnızca gerçekten izin verilen kaynakları açıkça tanımlayın. CORS ayrıca API kimlik doğrulamasının yerine geçmez; yalnızca tarayıcının yanıtı frontend koduna açıp açmayacağını belirler.Sık sorulan sorular
Postman'da çalışan istek neden tarayıcıda çalışmıyor?
Postman, tarayıcının same-origin ve CORS kurallarına tabi değildir. Bu nedenle Postman'da başarılı olan isteğin tarayıcıda da çalışması için API yanıtlarının uygun CORS başlıklarını içermesi gerekir.
CORS yalnızca frontend ve API farklı alan adındaysa mı oluşur?
Hayır. Protokol veya port farklılığı da origin'i değiştirir. Örneğin
http://example.com ile https://example.com veya https://example.com:3000 ile https://example.com:8000 aynı origin sayılmaz.