CORS Hatasını Anlamak ve FastAPI ile Doğru Çözmek
Beceri rehberi

CORS Hatasını Anlamak ve FastAPI ile Doğru Çözmek

Hazırlayan: Mindset Institute EditörlüğüGüncellendi: 5 dk okuma

CORS hatası, tarayıcının farklı bir origin'den gelen cevabı sunucudan izin gelmediği için engellemesidir. Çözüm tarayıcıda değil sunucuda, doğru başlıkları göndermektir; FastAPI'de bu adım adım nasıl yapılır, birlikte görelim.

Bir bakışta

  1. Hata tarayıcıdan gelir, çözüm sunucuya aittir. Tarayıcı, farklı origin'e yapılan isteğin cevabını, sunucu izin başlığı göndermediyse betiğe vermez.
  2. Origin üç parçadır: protokol, alan adı ve port. Yalnız port farklıysa bile iki adres farklı origin sayılır; localhost'ta ön yüz ile arka yüz bu yüzden sorun yaşar.
  3. FastAPI'de çözüm CORSMiddleware ile yapılır. İzin verilen origin, yöntem ve başlıklar açıkça tanımlanır; varsayılanlar kısıtlayıcıdır.
  4. Çerez ve kimlik bilgisi varsa joker karakter kullanılamaz. Kimlik bilgisi istendiğinde origin, yöntem ve başlıklar açıkça listelenmelidir.
  5. Hata ayıklamak için preflight isteğine bakın. Tarayıcı geliştirici araçlarındaki ağ sekmesi, OPTIONS isteğinin ve cevap başlıklarının ne olduğunu gösterir.

CORS hatası neden çıkar

Tarayıcıdaki betikler varsayılan olarak yalnızca kendi origin'lerinden gelen cevapları okuyabilir. MDN'ye göre fetch ve XMLHttpRequest, uygulamanın yüklendiği origin dışındaki bir cevabı, o cevap doğru CORS başlıklarını taşımıyorsa okuyamaz. CORS (Cross-Origin Resource Sharing), sunucunun bu kısıtı gevşetmesini sağlayan HTTP başlıkları mekanizmasıdır.

Origin, protokol, alan adı ve porttan oluşur. FastAPI belgeleri bunu açıkça örnekler: http://localhost, https://localhost ve http://localhost:8080 üç farklı origin'dir. Geliştirme sırasında ön yüz bir portta, arka yüz başka bir portta çalıştığı için bu hata sıkça karşınıza çıkar.

Hatayı sunucu değil tarayıcı üretir. Sunucu isteği alıp cevap bile verebilir; ama cevapta uygun izin başlığı yoksa tarayıcı cevabı betiğe vermez ve konsola hata yazar. Betiğe düşen hata ise genel bir ağ hatası olarak görünür; asıl neden konsolda yazar.

Bu yüzden çözüm ön yüz kodunu değiştirmek değil, arka yüzün doğru başlıkları göndermesini sağlamaktır.

Şekil 1

Tarayıcı engeller, sunucu başlıkla izin verir

CORS mantığı

  1. Farklı originÖn yüz ve arka yüz protokol, alan adı ya da port olarak farklı.
  2. Tarayıcı kısıtıCevap, izin başlığı yoksa betiğe verilmez.
  3. Sunucu izniArka yüz, izinli origin'i başlıkla bildirir.
Kaynak: MDN: CORSMindset Institute

Basit istek ve preflight

Tarayıcı her çapraz kaynak isteği için önceden izin sormaz. MDN'ye göre yöntemi GET, HEAD ya da POST olan; yalnızca güvenli listedeki başlıkları taşıyan; ve içerik türü form ya da düz metin olan istekler basit istektir ve doğrudan gönderilir.

Bunun dışındaki istekler preflight gerektirir. Örneğin JSON gönderen bir POST isteği içerik türü application/json olduğu için basit istek sayılmaz. Tarayıcı asıl istekten önce sunucuya bir OPTIONS isteği gönderir. Bu istek Origin, Access-Control-Request-Method ve gerekirse Access-Control-Request-Headers başlıklarını taşır. Sunucu cevabında asıl isteği onaylarsa, tarayıcı asıl isteği gönderir.

FastAPI belgelerine göre CORSMiddleware, Origin başlığı içeren ve Access-Control-Request-Method taşıyan OPTIONS isteklerini yakalar, uygun CORS başlıklarıyla cevaplar. Siz bu isteği ayrıca bir rota olarak yazmak zorunda kalmazsınız.

Bu ayrım hata ayıklamada önemlidir: asıl istek hiç sunucuya gelmemişse, çoğu zaman sorun preflight cevabındadır.

FastAPI'de CORSMiddleware ile yapılandırma

FastAPI'de çözüm, uygulamaya CORSMiddleware eklemektir:

from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

origins = [ "http://localhost:3000", "https://uygulamam.example", ]

app.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=True, allow_methods=["GET", "POST"], allow_headers=["Authorization", "Content-Type"], )

Bu örnekte ön yüzün çalıştığı iki adres izinli olarak listelenmiştir; yöntemler ve başlıklar da açıkça sayılmıştır.

Parametreler FastAPI belgelerine göre şöyledir: allow_origins izinli origin listesidir. allow_origin_regex bir düzenli ifadeyle origin eşleştirir. allow_methods izinli yöntemleri, allow_headers izinli istek başlıklarını belirler. allow_credentials çerez ve yetkilendirme başlığı gibi kimlik bilgilerinin desteklenip desteklenmeyeceğini söyler. expose_headers tarayıcıya okunabilir olacak cevap başlıklarını, max_age ise tarayıcının CORS cevaplarını ne kadar süre saklayabileceğini belirler.

Varsayılanlar kısıtlayıcıdır: origin listesi boştur, yalnız GET yöntemine izin verilir, kimlik bilgisi kapalıdır. İhtiyaç duyduğunuz her şeyi açıkça etkinleştirmeniz gerekir.

Şekil 2

Preflight cevabı asıl isteğin gönderilip gönderilmeyeceğini belirler

İstek akışı

  1. Tarayıcı OPTIONS gönderirOrigin ve istenen yöntem başlıklarıyla izin sorar.
  2. Middleware cevaplarCORSMiddleware uygun izin başlıklarını döner.
  3. Tarayıcı karşılaştırırOrigin ve yöntem izin verilenlerde mi?
  4. Asıl istek giderİzin varsa tarayıcı gerçek isteği gönderir.
  5. Cevap betiğe verilirCevap başlığı uygunsa JavaScript okuyabilir.
Kaynak: FastAPI ve MDN belgeleriMindset Institute

Çerez ve kimlik bilgisi ile joker karakter kısıtı

En sık yapılan yapılandırma hatalarından biri, çerezli ya da kimlik bilgili isteklerde joker karakter kullanmaktır. Geliştirme aşamasında allow_origins=["*"] her şeyi çözer gibi görünür; ancak çerez ya da Authorization başlığı eklediğinizde çalışmaz.

FastAPI belgeleri bunu açıkça söyler: allow_credentials True ise allow_origins, allow_methods ve allow_headers değerlerinin hiçbiri ["*"] olamaz; hepsi açıkça belirtilmelidir. MDN de aynı kuralı tarayıcı tarafından anlatır: kimlik bilgili istekte Access-Control-Allow-Origin için joker kullanılamaz, açık bir origin yazılmalıdır; izinli başlık ve yöntemler de açıkça listelenmelidir. Aksi halde tarayıcı cevabı engeller.

İstemci tarafında da kimlik bilgisi isteğinin açıkça etkinleştirilmesi gerekir. fetch için credentials: "include" seçeneği, XMLHttpRequest için withCredentials özelliği kullanılır. Üçüncü taraf çerez politikaları ise CORS yapılandırmasından bağımsız olarak geçerli kalır.

Doğru yaklaşım, izinli origin'leri bir liste halinde yazmak ve ortama göre (geliştirme, üretim) ayrı tanımlamaktır.

Şekil 3

Kimlik bilgisi varsa joker yerine açık liste yazılır

Sık yapılan hata

Çalışmaz
Doğrusu
allow_credentials açıkken allow_origins için joker
İzinli origin'leri açıkça listelemek
allow_methods ve allow_headers için joker
Yöntem ve başlıkları tek tek yazmak
İstemcide credentials seçeneğini unutmak
İstemcide credentials include kullanmak
Kaynak: FastAPI ve MDN belgeleriMindset Institute

Hata ayıklama: hatanın yerini bulmak

CORS hatası aldığınızda sırayla şunlara bakın. Önce tarayıcı konsolundaki mesajı okuyun; mesaj çoğu zaman eksik başlığı ya da uyuşmayan origin'i söyler. MDN, CORS hatalarının betiğe genel bir hata olarak yansıdığını, ayrıntı için konsola bakmak gerektiğini belirtir.

Sonra ağ sekmesinde OPTIONS isteğini bulun ve cevap başlıklarını inceleyin. Access-Control-Allow-Origin başlığı var mı, değeri ön yüzün tam origin'ine eşit mi? Yöntem ve istenen başlıklar izin listesinde mi?

Origin eşleşmesi tam olmalıdır. Sonda eğik çizgi, http yerine https ya da farklı port, farklı origin demektir. Listeye yazdığınız adres, tarayıcının gönderdiği Origin başlığıyla birebir aynı olmalıdır.

MDN ayrıca yönlendirme sorununu anar: preflight gerektiren bir isteğin ardından yönlendirme gelirse bazı tarayıcılar bunu reddeder. Adreste sonda eğik çizgi eksikliği gibi nedenlerle gelen yönlendirmeleri önlemek çözüm olabilir.

Kendi tarayıcınızda çalışan ama başka birinde çalışmayan durumlarda, istemcinin gönderdiği adresi ve ortam değişkenlerini kontrol edin; yanlış ortamın adresi izin listesinde olmayabilir.

Üretime çıkarken dikkat edilecekler

Geliştirmedeki ayarla üretimdeki ayar farklı olmalıdır. Geliştirmede yerel adresleri izinli tutmak yeterliyken, üretimde yalnızca gerçek ön yüz adreslerini listeleyin. Ortama göre değişen izinli origin listesini yapılandırma dosyasından ya da ortam değişkeninden okumak, yanlışlıkla gevşek ayarın üretime gitmesini önler.

CORS, tarayıcıya yönelik bir mekanizmadır. Tarayıcı dışındaki istemciler (komut satırı araçları, başka sunucular) bu başlıklara bağlı değildir. Bu yüzden CORS, kimlik doğrulama veya yetkilendirme yerine geçmez; bu kontrolleri ayrıca yapmanız gerekir.

Ön yüz ve arka yüzü aynı origin altında sunmak (örneğin ters vekil sunucu ile) CORS ihtiyacını tamamen ortadan kaldırabilir. Bu yaklaşım mimariye bağlıdır ve her projede uygun olmayabilir, ama çapraz kaynak yapılandırmasının karmaşasını azaltır.

Değişiklik sonrası tarayıcı önbelleğini hesaba katın: max_age ile preflight cevapları belirli süre saklanabilir, bu yüzden bir ayarı değiştirdiğinizde eski cevabı görmeye devam edebilirsiniz. Test ederken önbelleği temizleyin ya da gizli pencere kullanın.

Bu beceriyi Mindset programlarında nerede çalışırsınız

Python ile Web Geliştirme (FastAPI) eğitimi, Kimlik Doğrulama, Güvenlik ve CORS konusunu ayrı bir modül olarak işler. Bu modül, API'yi bir ön yüz uygulamasıyla birlikte çalıştıran geliştiriciler için tasarlanmıştır.

Aynı program Pydantic ile veri doğrulama, router yapısı, veritabanı entegrasyonu ve test ile dağıtım konularını da içerdiği için CORS yapılandırmasını bütün bir API'nin içinde ele alma imkânı verir.

İlgili Mindset programı

Python ile Web Geliştirme (FastAPI)

Sık sorulanlar

Sık sorulan sorular

CORS hatası ön yüzden mi arka yüzden mi çözülür?

Çözüm arka yüzdedir. Hatayı tarayıcı üretir, ama tarayıcı sunucunun izin başlığı göndermemesi nedeniyle cevabı engeller. Sunucu doğru Access-Control-Allow-Origin başlığını gönderirse sorun biter. Ön yüzde yalnızca kimlik bilgisi isteğini doğru etkinleştirmek gerekebilir.

Neden sadece tarayıcıda hata alıyorum, Postman'de almıyorum?

CORS tarayıcıya yönelik bir kısıttır. Tarayıcı dışındaki istemciler bu başlıklara bağlı olmadan isteği gönderir ve cevabı alır. Bu yüzden istek Postman'de çalışıp tarayıcıda engellenebilir; sorun sunucunun izin başlıklarındadır.

allow_origins için joker karakter kullanabilir miyim?

Kimlik bilgisi olmayan isteklerde kullanılabilir. Ancak allow_credentials açıksa FastAPI belgelerine göre allow_origins, allow_methods ve allow_headers için joker kullanamazsınız; hepsini açıkça yazmanız gerekir. Çerezli oturumlar için izinli origin'leri listelemek zorunludur.

Preflight isteği nedir ve ne zaman gönderilir?

Tarayıcının asıl istekten önce gönderdiği OPTIONS isteğidir ve sunucudan izin sorar. MDN'ye göre basit olmayan istekler, örneğin JSON gövdeli POST ya da özel başlıklı istekler için gönderilir. Sunucu onaylarsa tarayıcı asıl isteği yollar.

Origin listesine hangi adresi yazmalıyım?

Tarayıcının gönderdiği Origin başlığının birebir aynısını: protokol, alan adı ve port dahil. Sonda eğik çizgi, http yerine https ya da farklı port farklı origin sayılır. Ön yüzün çalıştığı gerçek adresleri ortama göre ayrı ayrı listeleyin.

CORS Hatası Nasıl Çözülür? FastAPI CORSMiddleware