CORS hatası, tarayıcının başka bir kökenden gelen yanıtı güvenlik kuralları gereği kodunuza vermediğini gösterir. Çözümün neredeyse her zaman sunucu tarafında olduğunu baştan bilmek işinizi kolaylaştırır: eksik veya hatalı bir Access-Control-* başlığını düzeltirsiniz, ya da isteği sunucunun izin verdiği biçime getirirsiniz. Firefox konsolu her hatanın sonuna kısa bir "Reason" (neden) metni ekler; bu metin sorunun hangi başlıkta olduğunu doğrudan söyler.

Bu yazıda MDN'nin listelediği on beş CORS neden mesajını tek tek ele alıyoruz: mesajın ne anlama geldiğini, en olası nedenini ve çözümünü. CORS'un nasıl çalıştığını, basit istek ve ön uçuş farkını henüz bilmiyorsanız önce CORS nedir rehberini okumanızı öneririz. Sunucu yapılandırmasında ve yanıt başlıklarında yapılacak değişiklikler için örnekler HTTP başlık satırları olarak verildi.

CORS hatasını tanımak

CORS hatasını tanımak: Geliştirici araçlarını açın ve hatayı yeniden oluşturun., Konsolda CORS mesajını ve neden metnini bulun., Ağ (Network) sekmesinde ilgili isteği seçin; ön...

Yapılandırma hatalı olduğunda Firefox konsolu aşağıdakine benzer bir mesaj gösterir. Parantez içindeki "Reason" kısmı, bu yazının başlıklarında geçen metinlerden biridir:

http
Cross-Origin Request Blocked: The Same Origin Policy disallows
reading the remote resource at https://some-url-here. (Reason:
additional information here).

Önemli bir ayrıntı: güvenlik nedeniyle CORS hatasının ayrıntıları JavaScript'e bildirilmez. Kodunuz yalnızca bir hata oluştuğunu bilir; fetch() sözü reddedilir ama nedenini hata nesnesinden okuyamazsınız. Gerçek nedeni öğrenmenin tek yolu tarayıcının geliştirici araçlarındaki konsola bakmaktır. Hata ayıklarken şu sırayı izleyin:

  • Geliştirici araçlarını açın ve hatayı yeniden oluşturun.
  • Konsolda CORS mesajını ve neden metnini bulun.
  • Ağ (Network) sekmesinde ilgili isteği seçin; ön uçuş varsa OPTIONS isteğini ayrıca inceleyin.
  • Yanıt başlıklarında Access-Control-Allow-Origin ve diğer Access-Control-* başlıklarının değerlerini isteğin Origin başlığıyla karşılaştırın.

Her CORS hatası bir yapılandırma hatası da değildir. Uzak servis bazı kökenlerden gelen istekleri bilerek reddediyor olabilir; bu durumda yapılacak şey servisin belgelerine bakmaktır.

Hata mesajları, nedenleri ve çözümleri

Hızlı özet tablosu

Neden mesajı (kısaltılmış)Kimin düzeltmesi gerekirİlk bakılacak yer
CORS disabledKullanıcıTarayıcı ayarı
CORS request did not succeedAğ veya sunucuBağlantı, sertifika, eklentiler
Origin cannot be addedOrtamAyrıcalıklı betik bağlamı
external redirect not allowedİstemciİstek URL adresi
CORS request not HTTPİstemcifile: ile açılan sayfa
Allow-Origin missingSunucuAccess-Control-Allow-Origin
Allow-Origin does not matchSunucuBaşlıktaki köken değeri
Credential is not supported if *Sunucu veya istemciJoker ve credentials
Did not find methodSunucu veya istemciAccess-Control-Allow-Methods
expected true in Allow-CredentialsSunucu veya istemciAccess-Control-Allow-Credentials
preflight channel did not succeedSunucuOPTIONS yanıtı
invalid token in Allow-MethodsSunucuYöntem listesindeki yazım
invalid token in Allow-HeadersSunucuBaşlık listesindeki yazım
missing token in Allow-HeadersSunucu veya istemciİzin verilen başlıklar
Multiple Allow-Origin not allowedSunucuYinelenen başlık

Reason: CORS disabled

http
Reason: CORS disabled

CORS gerektiren bir istek yapıldı ama kullanıcının tarayıcısında CORS kapatılmış. Firefox'ta bunu yapan ayar content.cors.disable tercihidir; değeri true olduğunda tüm CORS istekleri bu hatayla başarısız olur. Çözüm kullanıcının bu ayarı geri açmasıdır; sitenin kodunda yapılacak bir şey yoktur.

Reason: CORS request did not succeed

http
Reason: CORS request did not succeed

Bu mesaj aslında CORS'la doğrudan ilgili değildir: HTTP bağlantısı ağ veya protokol düzeyinde başarısız olmuştur. MDN'ye göre sık nedenlerden biri, istek engelleyen bir tarayıcı eklentisidir (reklam engelleyici, gizlilik koruyucu).

Çözüm için geliştirici araçlarının ağ sekmesinde isteğin DNS çözümlemesi, zaman aşımı, reddedilen bağlantı veya TLS el sıkışması hatası yüzünden mi düştüğüne bakın. Eklentileri kapatıp gizli pencerede deneyin, süresi dolmuş veya geçersiz sertifikaları düzeltin. HTTPS bir sayfadan HTTP bir kaynağa istek atmak da bu hataya yol açar; API'yi HTTPS üzerinden sunun (karma içerik hatası ve HTTPS rehberi). Sunucu ön uçuşa yanıt verip asıl isteğe hiç yanıt vermeden çöküyorsa da aynı mesajı görürsünüz. Yerel geliştirme sunucusu kullanıyorsanız şema ve portun doğru olduğundan ve servisin çalıştığından emin olun.

Reason: CORS header 'Origin' cannot be added

http
Reason: CORS header 'Origin' cannot be added

Tarayıcı, isteğe zorunlu Origin başlığını ekleyememiştir; her CORS isteğinde bu başlık bulunmak zorundadır. MDN bunun, örneğin birden çok alan adının içeriğine erişebilen yükseltilmiş ayrıcalıklarla çalışan JavaScript kodunda görülebileceğini belirtir. Normal bir web sayfasında nadiren karşılaşılır.

Reason: CORS request external redirect not allowed

http
Reason: CORS request external redirect not allowed

Sunucu CORS isteğine, isteğin kökeninden farklı bir kökene giden bir yönlendirmeyle (301, 307 veya 308 ve farklı bir Location) cevap vermiştir; bu CORS isteklerinde izin verilmez. Örneğin https://service.tld/fetchdata isteği https://anotherservice.net/getdata adresine yönlendiriliyorsa istek bu şekilde başarısız olur.

Çözüm, kodunuzda doğrudan yönlendirmenin gösterdiği yeni URL'yi kullanmaktır; böylece yönlendirme hiç yaşanmaz.

Reason: CORS request not HTTP

http
Reason: CORS request not HTTP

CORS istekleri yalnızca HTTP veya HTTPS şemasıyla yapılabilir. Bu hata en sık, sayfayı bir dosya olarak (file:///) açtığınızda görülür. Firefox ve Chrome dahil birçok tarayıcı yerel dosyaların kökenini varsayılan olarak opak (opaque) kabul eder; yani aynı klasördeki iki dosya bile aynı kökenden sayılmaz. Kökeni URL nesnesiyle kontrol ettiğinizde bunu görebilirsiniz:

javascript
console.log(new URL("file:///C:/proje/index.html").origin); // null
console.log(new URL("http://localhost:8080/index.html").origin); // http://localhost:8080

Çözüm, projeyi yerel bir HTTP sunucusu üzerinden açmaktır. Tüm dosyalar localhost üzerinden aynı şema ve portla sunulduğu için aynı kökene sahip olur ve kökenler arası hata oluşmaz.

Reason: CORS header 'Access-Control-Allow-Origin' missing

http
Reason: CORS header 'Access-Control-Allow-Origin' missing

En sık görülen CORS hatasıdır: yanıtta Access-Control-Allow-Origin başlığı hiç yoktur. Sunucu sizin kontrolünüzdeyse isteği yapan sitenin kökenini bu başlığa ekleyin. Herkese açık bir API için * kullanılabilir; MDN özel API'lerde jokerin asla kullanılmaması gerektiğini, ayrıca jokerin kimlik bilgisi gönderilmesini engellediğini vurgular.

Joker kullanmadan birden çok siteye izin vermek için sunucu gelen Origin değerini okuyup (bir izin listesiyle doğrulayarak) aynı değeri Access-Control-Allow-Origin olarak yazmalı ve Vary: Origin başlığını eklemelidir. Apache'de Header set, Nginx'te add_header yönergesiyle bu başlık eklenir. Sunucu sizin değilse seçenekleriniz sınırlıdır: isteği basit isteğe çevirmek, yanıtı okumanız gerekmiyorsa mode: "no-cors" kullanmak ya da kendi kontrolünüzdeki bir sunucu üzerinden vekil (proxy) istek yapmak.

http
Access-Control-Allow-Origin: https://example.com
Vary: Origin

Reason: CORS header 'Access-Control-Allow-Origin' does not match 'xyz'

http
Reason: CORS header 'Access-Control-Allow-Origin' does not match 'xyz'

İsteği yapan köken, Access-Control-Allow-Origin başlığında izin verilen kökenle eşleşmiyor. Yanıtta birden fazla Access-Control-Allow-Origin başlığı bulunması da bu hataya yol açabilir.

Sunucunun sizin kökeninizi yazdığından, yanıtta bu başlıktan yalnızca bir tane olduğundan ve başlığın tek bir köken içerdiğinden emin olun. MDN özellikle protokolün (HTTP veya HTTPS) kökenin parçası olduğunu ve yazılması gerektiğini hatırlatır: https://foo.example sayfasına http://foo.example değeri eşleşmez.

Reason: Credential is not supported if the CORS header 'Access-Control-Allow-Origin' is '*'

http
Reason: Credential is not supported if the CORS header 'Access-Control-Allow-Origin' is '*'

İstek kimlik bilgisi bayrağıyla yapıldı ama sunucu Access-Control-Allow-Origin değeri olarak joker kullanıyor; joker kimlik bilgisiyle birlikte kullanılamaz.

İstemci tarafında çözmek için kimlik bilgisi istemeyin: Fetch API'de credentials değerini "omit" yapın, XMLHttpRequest'te withCredentials değerini true yapmayın, EventSource kullanıyorsanız withCredentials değerinin varsayılan false olarak kaldığından emin olun. Sunucu tarafında çözmek için jokeri, istemcinin yüklendiği kökenle değiştirin.

Reason: Did not find method in CORS header 'Access-Control-Allow-Methods'

http
Reason: Did not find method in CORS header 'Access-Control-Allow-Methods'

İsteğin kullandığı HTTP yöntemi, yanıtın Access-Control-Allow-Methods listesinde yok. Örneğin yanıt Access-Control-Allow-Methods: GET,HEAD,POST içeriyorsa bir PUT isteği bu hatayla başarısız olur.

Ya kodunuzda yalnızca izin verilen yöntemleri kullanın ya da sunucu listesine gerekli yöntemi ekleyin. Listede tanınmayan bir yöntem adı varsa farklı bir hata (invalid token) görürsünüz.

Reason: expected 'true' in CORS header 'Access-Control-Allow-Credentials'

http
Reason: expected 'true' in CORS header 'Access-Control-Allow-Credentials'

İstek kimlik bilgisi kullanıyor ama sunucunun Access-Control-Allow-Credentials başlığı true değil (veya hiç yok).

İstemcide çözüm, kimlik bilgisi istememektir: credentials: "omit", XHR'de withCredentials kapalı, EventSource'ta withCredentials false. Sunucuda çözüm, bu başlığın değerini true yapmaktır; bu durumda Access-Control-Allow-Origin değerinin de joker değil açık bir köken olması gerekir.

Reason: CORS preflight channel did not succeed

http
Reason: CORS preflight channel did not succeed

İstek ön uçuş gerektiriyor ama ön uçuş gerçekleştirilemedi. MDN iki olası neden sayar: daha önce ön uçuşu yapılmış bir kökenler arası istek için yeniden ön uçuş yapılmasına izin verilmemesi (kodunuzun her bağlantıda yalnızca bir kez ön uçuş yaptığından emin olun) ve ön uçuş isteğinin herhangi bir ağ hatasına uğraması. Pratikte sunucunun OPTIONS isteklerine hiç yanıt vermediği veya hata döndürdüğü durumları da ağ sekmesinde kontrol edin.

Reason: invalid token 'xyz' in CORS header 'Access-Control-Allow-Methods'

http
Reason: invalid token 'xyz' in CORS header 'Access-Control-Allow-Methods'

Sunucunun ön uçuşa verdiği Access-Control-Allow-Methods başlığında tarayıcının tanımadığı en az bir yöntem adı var. Değer, virgülle ayrılmış HTTP yöntem adlarından oluşmalıdır.

Çözüm büyük ihtimalle sunucu tarafındadır: yapılandırmadan geçersiz veya bilinmeyen yöntem adını kaldırın. MDN ayrıca kullandığınız tarayıcının veya HTTP kütüphanesinin güncel olduğunu kontrol etmeyi önerir.

Reason: invalid token 'xyz' in CORS header 'Access-Control-Allow-Headers'

http
Reason: invalid token 'xyz' in CORS header 'Access-Control-Allow-Headers'

Ön uçuş yanıtındaki Access-Control-Allow-Headers listesinde tarayıcının geçersiz saydığı en az bir başlık adı var.

Sunucu yapılandırmasını düzeltip listeyi yalnızca geçerli başlık adlarıyla, virgülle ayrılmış biçimde gönderin.

Reason: missing token 'xyz' in CORS header 'Access-Control-Allow-Headers' from CORS preflight channel

http
Reason: missing token 'xyz' in CORS header 'Access-Control-Allow-Headers' from CORS preflight channel

İsteğiniz, sunucunun Access-Control-Allow-Headers listesinde açıkça izin vermediği bir başlık kullanıyor. Örneğin istekte X-Custom-Information veya Authorization varsa ama sunucu bunları listelemiyorsa ön uçuş bu hatayla reddedilir.

Ya sunucu listeye bu başlığı eklemeli ya da siz başlığı kullanmaktan vazgeçmelisiniz. Sunucu sizin değilse istemci tarafı seçenekleri aşağıdaki bölümde.

Reason: Multiple CORS header 'Access-Control-Allow-Origin' not allowed

http
Reason: Multiple CORS header 'Access-Control-Allow-Origin' not allowed

Sunucu birden fazla Access-Control-Allow-Origin başlığı gönderdi; buna izin verilmez. Tarayıcı bu başlıkta yalnızca tek bir köken veya null kabul eder, köken listesi kabul etmez.

Bu durum çoğunlukla başlığın iki katmanda birden eklenmesiyle oluşur (örneğin hem uygulama kodu hem web sunucusu yapılandırması). Aynı ada sahip iki başlık değeri, Headers nesnesinde nasıl birleştiğine bakınca sorun daha net görünür:

javascript
const h = new Headers();
h.append("Access-Control-Allow-Origin", "https://a.example");
h.append("Access-Control-Allow-Origin", "https://b.example");
console.log(h.get("access-control-allow-origin")); // https://a.example, https://b.example

Çözüm, başlığı tek bir yerde üretmek ve izin listesindeki kökenlerden yalnızca isteği yapana karşılık gelen değeri yazmaktır.

Sunucu sizin değilse: istemci tarafı seçenekler

Sunucu sizin değilse: istemci tarafı seçenekler: Ön uçuşu tetiklemeyin, Yanıtı okumanız gerekmiyorsa no-cors kullanın, Vekil sunucu kullanın

MDN, CORS hatalarının çoğunun yalnızca sunucuda çözülebileceğini hatırlatır; yine de istemci tarafında yapabileceğiniz üç şey vardır:

  • Ön uçuşu tetiklemeyin: yalnızca GET, HEAD veya POST kullanın, yalnızca güvenli listedeki başlıkları ayarlayın ve Content-Type olarak yalnızca application/x-www-form-urlencoded, multipart/form-data veya text/plain seçin. Böylece ön uçuşla ilgili bir hata sınıfından tamamen kaçınırsınız.
  • Yanıtı okumanız gerekmiyorsa no-cors kullanın: analitik beacon'ları veya service worker önbelleği için uygundur. Yanıt opak olur: durum 0, başlıklar boş, gövde okunamaz.
  • Vekil sunucu kullanın: isteği kendi kontrolünüzdeki bir sunucuya gönderin, o sunucu kaynağı alıp uygun CORS başlıklarıyla size döndürsün. Bu yöntem gecikme ekler ve vekile bağımlılık oluşturur ama diğer seçenekler yoksa çalışır.
javascript
fetch("https://api.example.com/log", {
  method: "POST",
  mode: "no-cors",
  body: data,
});

Yanıt başlıklarını sistemli kontrol etmek

Ağ sekmesinden kopyaladığınız yanıt başlıklarını hızlıca değerlendirmek için aşağıdaki gibi küçük bir teşhis fonksiyonu yazabilirsiniz. Fonksiyon, tarayıcının tüm kontrollerini değil; bu yazıdaki en yaygın altı hatanın mantığını modeller ve sonucu MDN sayfalarının kimlikleriyle döndürür. Örnekler Node.js 24 ile çalıştırıldı:

javascript
function corsTeshis({ origin, credentials, method, yanit }) {
  const acao = yanit.get("Access-Control-Allow-Origin");
  if (acao === null) return "CORSMissingAllowOrigin";
  if (acao.includes(",")) return "CORSMultipleAllowOriginNotAllowed";
  if (credentials === "include" && acao === "*") {
    return "CORSNotSupportingCredentials";
  }
  if (acao !== "*" && acao !== origin) {
    return "CORSAllowOriginNotMatchingOrigin";
  }
  if (credentials === "include" && yanit.get("Access-Control-Allow-Credentials") !== "true") {
    return "CORSMissingAllowCredentials";
  }
  const izinli = yanit.get("Access-Control-Allow-Methods");
  if (method && izinli !== null) {
    const liste = izinli.split(",").map((m) => m.trim().toUpperCase());
    if (!liste.includes(method)) return "CORSMethodNotFound";
  }
  return "sorun görünmüyor";
}

const o = "https://foo.example";
const ornekler = [
  { origin: o, yanit: new Headers() },
  { origin: o, yanit: new Headers({ "Access-Control-Allow-Origin": "https://foo.example, https://bar.example" }) },
  { origin: o, credentials: "include", yanit: new Headers({ "Access-Control-Allow-Origin": "*" }) },
  { origin: o, yanit: new Headers({ "Access-Control-Allow-Origin": "http://foo.example" }) },
  { origin: o, credentials: "include", yanit: new Headers({ "Access-Control-Allow-Origin": o }) },
  { origin: o, method: "PUT", yanit: new Headers({ "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET,HEAD,POST" }) },
  { origin: o, method: "POST", yanit: new Headers({ "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET,HEAD,POST" }) },
];
for (const x of ornekler) console.log(corsTeshis(x));
// CORSMissingAllowOrigin
// CORSMultipleAllowOriginNotAllowed
// CORSNotSupportingCredentials
// CORSAllowOriginNotMatchingOrigin
// CORSMissingAllowCredentials
// CORSMethodNotFound
// sorun görünmüyor

Dördüncü örnekte tek fark protokoldür ve bu bile eşleşmeyi bozar. Beşinci örnekte köken doğru yazılmış ama kimlik bilgili istekte Access-Control-Allow-Credentials: true eksik kalmıştır.

Sık yapılan hatalar

  • Tarayıcının CORS korumasını kapatmayı çözüm sanmak: yalnızca sizin makinenizde çalışır, kullanıcılarınızın tarayıcısında hata devam eder.
  • Hatayı catch bloğundan anlamaya çalışmak: nedeni yalnızca konsolda görünür.
  • no-cors ile veri okumaya çalışmak: opak yanıtta gövde her zaman okunamaz; bu mod bir okuma çözümü değildir.
  • Hata sayfalarında CORS başlığını unutmak: sunucu 4xx veya 5xx yanıtlarına başlık eklemezse asıl hata yerine CORS hatası görürsünüz.
  • Başlığı iki yerde eklemek: uygulama ve web sunucusu birlikte eklerse yinelenen başlık hatası çıkar.
  • Yerel dosyadan test etmek: file:/// kökeni opaktır; yerel bir sunucu kullanın.

Sık Sorulan Sorular

CORS hatasını JavaScript koduyla düzeltebilir miyim?

Genellikle hayır. İzni veren taraf sunucudur. İstemcide yalnızca isteği basit isteğe çevirebilir, okuma gerekmiyorsa no-cors kullanabilir veya kendi sunucunuz üzerinden vekil istek yapabilirsiniz.

Chrome'daki hata metni neden farklı?

Bu yazıdaki neden metinleri MDN'nin belgelediği Firefox konsol mesajlarıdır. Diğer tarayıcılar aynı durumu farklı cümlelerle bildirebilir; mesajdaki başlık adına bakarak bu listedeki karşılığını bulabilirsiniz.

Postman'de çalışan istek tarayıcıda neden CORS hatası veriyor?

CORS bir tarayıcı kuralıdır; tarayıcı dışı istemciler aynı köken politikasını uygulamaz. Sunucu doğru Access-Control-* başlıklarını göndermediği sürece tarayıcı yanıtı sayfanıza vermez.

Failed to fetch hatası her zaman CORS mu demektir?

Hayır. fetch() sözü ağ hatalarında da TypeError ile reddedilir; bağlantı kopması, DNS hatası veya sertifika sorunu da koddan bakınca CORS engeliyle aynı görünür. Ayırt etmek için konsola ve ağ sekmesine bakın. Ayrıntılar Web API hataları yazısında.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Web API öğrenme rehberi · CORS nedir · Fetch API kullanımı · Request, Response ve Headers · DOMException ve güvenli bağlam hataları · Karma içerik hatası