---
title: "CORS Hatası Nedir? Blocked by CORS Policy Nasıl Çözülür?"
description: "CORS hatası, tarayıcının başka bir origin'den gelen yanıtı sayfanıza vermemesidir. Blocked by CORS policy mesajının nedenini ve çözümünü anlatıyoruz."
url: https://proxynet.io/tr/blog/cors-error
date: 2026-10-06
author: "Acar Diveroli"
category: "Nasıl Yapılır, Web Scraping"
lang: tr
---

# CORS Hatası Nedir? Blocked by CORS Policy Nasıl Çözülür?

Ön yüzünüz (frontend) `http://localhost:5173` adresinde, API'niz `http://localhost:3001` adresinde çalışıyor. API curl'de ve Postman'de JSON döndürüyor, ama tarayıcıda `fetch()` çağrısı `TypeError: Failed to fetch` hatası veriyor ve konsolda şu satır çıkıyor: `Access to fetch at 'http://localhost:3001/api/products' from origin 'http://localhost:5173' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.` Oysa API'nin log'una bakınca isteğin geldiğini ve `200` ile cevaplandığını görüyorsunuz.

Bu yazıda origin'in ne olduğunu, yanıtı neden sunucunun değil tarayıcının engellediğini ve basit isteklerle preflight isteklerinin farkını anlatıyoruz. Ardından Chrome'un mesajlarını tek tek açıklıyoruz. Express, Flask ve Vite için denenmiş çözümleri, size ait olmayan API'ler için bir sunucu rotasını ve web scraping (veri kazıma) kodunun neden hiç CORS hatası görmediğini de gösteriyoruz.

> **Not: Kısa cevap**
>
> CORS hatası, tarayıcının başka bir origin'den gelen yanıtı aldığı hâlde JavaScript kodunuza vermediği anlamına gelir; çünkü sunucu, sayfanızın origin'ini içeren bir `Access-Control-Allow-Origin` header'ı göndermemiştir. Origin; şema, alan adı ve portun birleşimidir, bu yüzden `localhost:5173` ile `localhost:3001` farklı origin'lerdir. Çözüm sunucudadır: tam origin'inize izin verin, `OPTIONS` preflight isteklerini cevaplayın, kullandığınız yöntemleri ve header'ları listeleyin. Yerel çalışırken geliştirme sunucusunun proxy ayarı API'yi aynı origin'e taşır; size ait olmayan bir API'yi kendi sunucunuzdan çağırın. `mode: "no-cors"`, tarayıcı eklentileri, herkese açık CORS proxy'leri, VPN ya da proxy bu hatayı çözmez.

## CORS hatası nedir?

CORS hatası, tarayıcının bir yanıtı betiğinize vermeyi reddetmesidir. CORS (Cross-Origin Resource Sharing, kaynaklar arası kaynak paylaşımı), sunucunun hangi başka origin'lerin yanıtlarını okuyabileceğini tarayıcıya bildirdiği HTTP yanıt header'larıdır. [Fetch Standardı](https://fetch.spec.whatwg.org/#http-cors-protocol) bu izni varsayılan olarak kapalı tutar ve sunucunun açıkça vermesini ister: güvenlik duvarının ya da oturum açma ekranının arkasındaki veriler başka sitelere sızmasın diye. Eşleşen header yoksa tarayıcı varsayılan kuralını, yani aynı köken politikasını (same-origin policy) uygular ve okumayı engeller.

Bundan üç sonuç çıkar. Hatayı tarayıcı ürettiği için sunucu log'ları normal görünür. Kodunuz yalnız genel bir hata alır: `fetch()` ile `TypeError: Failed to fetch`, Axios ile `ERR_NETWORK` kodlu `AxiosError: Network Error`; asıl neden yalnız konsolda görünür. Çözüm de isteği gönderen kodda değil, cevap veren sunucudadır.

## Origin nedir, aynı köken politikası neyi engeller?

Origin (köken), bir URL'nin şeması, alan adı ve portudur. İki URL'nin origin'i ancak bu üçü de aynıysa aynıdır:

- `http://localhost:5173` ve `http://localhost:3001`: portlar farklı, origin'ler farklı.
- `http://example.com` ve `https://example.com`: şemalar farklı.
- `https://example.com` ve `https://api.example.com`: alan adları farklı; alt alan adı ayrı bir origin'dir.
- `https://example.com/shop` ve `https://example.com/api`: aynı origin; yol (path) hesaba katılmaz.

Aynı köken politikası, bir sayfanın başka sitelerden resim, betik ve stil dosyası yüklemesine, onlara link vermesine ve form göndermesine izin verir. Engellediği şey okumadır: bir betik, başka bir origin'den gelen yanıtı, o origin izin vermedikçe okuyamaz ([MDN: Same-origin policy](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy)). CORS, sunucunun bu izni verme yoludur.

## Origin'ler arası bir istek adım adım nasıl işler?

1. A origin'indeki sayfanız, B origin'indeki bir URL için `fetch()` çağırır.
2. Tarayıcı isteğin "basit" olup olmadığına bakar. Basit değilse önce bir preflight isteği gönderir (sonraki bölüm).
3. İsteğe `Origin: http://localhost:5173` gibi bir `Origin` header'ı ekler. Betikler bu header'ı ne ekleyebilir ne de silebilir.
4. Sunucu kodunu çalıştırır ve cevap verir. Kodun yaptığı iş bu noktada tamamlanmıştır.
5. Tarayıcı yanıttaki `Access-Control-Allow-Origin` değerini sayfanın origin'iyle karşılaştırır. Tam eşleşmeyi ya da kimlik bilgisi gönderilmemişse `*` değerini kabul eder.
6. Eşleşme varsa yanıt kodunuza verilir; yoksa tarayıcı yanıtı atar, promise reddedilir ve konsol nedeni yazar.

Gözden kaçan nokta 4. adımdır: CORS, isteğin sunucuya ulaşmasını engellemez; curl, betikler ve diğer sunucular 5. adımı hiç uygulamaz. CORS ziyaretçiyi korur: ziyaretçinin açtığı bir sayfa, onun çerezlerini kullanarak başka sitelerdeki verilerini okuyamaz. API'nizi ise korumaz.

## Basit istek ve preflight isteği: GET neden çalışıyor da POST çalışmıyor?

Bir istek, `GET`, `HEAD` ya da `POST` yöntemini ve yalnız izinli header'ları kullanıyorsa "basit" sayılır: `Accept`, `Accept-Language`, `Content-Language`, `Range` ve değeri `application/x-www-form-urlencoded`, `multipart/form-data` ya da `text/plain` olan `Content-Type`. Geri kalan her istek için önce preflight (ön kontrol) yapılır: tarayıcı `Access-Control-Request-Method` ve `Access-Control-Request-Headers` header'larını taşıyan bir `OPTIONS` isteği gönderir, asıl isteği ancak gelen cevap izin veriyorsa yollar ([MDN: CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS)). JSON gövdesi, `Authorization` header'ı, `PUT`, `PATCH`, `DELETE` ya da `X-Request-ID` gibi özel bir header bunu tetikler.

5173 portundaki bir sayfadan, 3001 portunda çalışan ve hiç CORS header'ı göndermeyen bir API'ye basit bir `GET` ve JSON gövdeli bir `POST` gönderdik. API'nin log'u şöyleydi:

```text
[no-cors-api] GET /api/products origin=http://localhost:5173
[no-cors-api] OPTIONS /api/products origin=http://localhost:5173
```

`GET` isteği `200` ve verinin kendisiyle cevaplandı, tarayıcı yine de engelledi. `POST` isteğinden sunucuya yalnız preflight ulaştı; o başarısız olunca `POST` hiç gönderilmedi. Form verisi gönderen bir `POST` gibi basit bir istek ise, sayfa hata görse bile sunucuya ulaşır ve işlenir. Bu tür işlemleri CORS ile değil, kimlik doğrulama ve CSRF token'larıyla koruyun.

`Access-Control-Max-Age` header'ı, tarayıcının preflight cevabını önbellekte tutmasını sağlar. Fetch Standardı'na göre varsayılan süre 5 saniyedir; Chromium üst sınırı 2 saat, Firefox 24 saat olarak uygular.

## "Blocked by CORS policy" mesajları ne anlama gelir?

Chrome'un her mesajı `Access to fetch at '<URL>' from origin '<origin>' has been blocked by CORS policy:` ile başlar; Axios ve `XMLHttpRequest` kullanıyorsanız başlangıç `Access to XMLHttpRequest at` olur. Chromium bu metinleri kaynak kodunda İngilizce olarak sabit tutar; Türkçe arayüzde de İngilizce görünürler. İki nokta üst üsteden sonraki kısım nedeni söyler. Tablodaki ilk beş mesajı Chromium 152 tabanlı bir tarayıcıda yaptığımız testte birebir gördük; diğerleri Chromium'un kaynak kodundan alındı.

| "blocked by CORS policy:" sonrasındaki mesaj | Anlamı | Çözüm |
|---|---|---|
| `No 'Access-Control-Allow-Origin' header is present on the requested resource.` | Yanıtta CORS header'ı yok: kurulmamış ya da bir hata sayfası cevap vermiş | Origin'inize izin verin; gerçek durum kodunu kontrol edin |
| `Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present…` | `OPTIONS` cevabında CORS header'ı yok; asıl istek gönderilmedi | `OPTIONS` isteğini CORS header'larıyla cevaplayın |
| `The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.` | Çerez gönderildi, sunucu `*` ile cevap verdi | Tam origin ve `Access-Control-Allow-Credentials: true` |
| `Request header field x-debug is not allowed by Access-Control-Allow-Headers in preflight response.` | Gönderdiğiniz bir header'a izin verilmemiş | İzin verin ya da göndermeyin |
| `Method PATCH is not allowed by Access-Control-Allow-Methods in preflight response.` | Yönteme izin verilmemiş | Yöntemi listeye ekleyin |
| `The 'Access-Control-Allow-Origin' header has a value '…' that is not equal to the supplied origin.` | Başka bir origin'e izin verilmiş: yanlış port, `http`, sonda eğik çizgi | İzin listesini düzeltin |
| `The 'Access-Control-Allow-Origin' header contains multiple values '…', but only one is allowed.` | Header'ı iki katman ekliyor, örneğin uygulama ve nginx | Tek bir yerde ekleyin |
| `Response to preflight request doesn't pass access control check: It does not have HTTP ok status.` | `OPTIONS` isteği `401`, `404`, `405` ya da `500` aldı | `OPTIONS` isteğini kimlik doğrulamadan önce geçirin |
| `Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.` | `OPTIONS` isteği yönlendirildi, örneğin `https` adresine ya da giriş sayfasına | Doğrudan son URL'yi çağırın |

Eski Chrome sürümleri ilk mesaja `mode: 'no-cors'` öneren bir cümle ekliyordu; Chromium, yanılttığı için bu ipucunu Mart 2025'te kaldırdı (nedenini SSS'de anlatıyoruz). Firefox aynı sorunu `Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at … (Reason: CORS header 'Access-Control-Allow-Origin' missing)` biçiminde yazar.

## Asıl nedeni nasıl bulursunuz?

Geliştirici araçlarını F12 ile açın ve **Console** (Türkçe arayüzde **Konsol**) sekmesindeki satırı okuyun: hangi URL, hangi origin, hangi neden. **Network** (Türkçe arayüzde **Ağ**) sekmesinde engellenen isteğin **Status** (**Durum**) sütununda sayı yerine `CORS error` (Türkçe arayüzde `CORS hatası`) yazar. Preflight yapılan bir çağrının ayrıca bir `OPTIONS` kaydı vardır; bu kaydın **Initiator** (**Başlatan**) sütununda `Preflight` (Türkçe arayüzde `Yayın öncesi`) görünür. Header'ları görmek için kayda tıklayın.

Gerçek durum kodu kolayca gözden kaçar. Testimizde bir ağ geçidi (gateway) CORS header'ı olmadan `502` döndürdü: konsolda yalnız "No 'Access-Control-Allow-Origin' header" satırı vardı, aynı URL'yi `curl -i` ile çağırınca ise `HTTP/1.1 502 Bad Gateway` satırı çıktı. nginx'in, yük dengeleyicilerin ya da çöken bir uygulamanın hata sayfalarında CORS header'ı nadiren bulunur; bu yüzden bir kesinti CORS sorunu gibi görünür. nginx'in `add_header` yönergesi, `always` parametresi eklenmedikçe yalnız 200, 201, 204, 206, 301, 302, 303, 304, 307 ve 308 yanıtlarına uygulanır ([nginx dokümantasyonu](https://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header)).

## API sizinse CORS hatası nasıl çözülür?

Header'ları API'nin kendisinden, ön yüzünüzün tam origin'leri için gönderin. Her örneği 6 Ekim 2026'da Node.js 24.11, Express 5.2.1, cors 2.8.6, Vite 8.3.3, Python 3.13, Flask 3.1.3 ve Flask-CORS 6.0.5 ile denedik.

### Express

`npm install express cors` ile kurun ve `package.json` dosyasına `"type": "module"` ekleyin.

```js
// server.js: tek bir ön yüze izin veren API (Express 5, cors 2.8)
import express from "express";
import cors from "cors";

const app = express();

app.use(cors({
  origin: ["https://app.example.com", "http://localhost:5173"],
  methods: ["GET", "POST", "PUT", "DELETE"],
  allowedHeaders: ["Content-Type", "Authorization"],
  credentials: true,
  maxAge: 600,
}));
app.use(express.json());

app.get("/api/products", (req, res) => {
  res.json([{ id: 1, name: "Desk lamp" }]);
});

app.post("/api/products", (req, res) => {
  res.status(201).json({ created: req.body });
});

app.listen(3000, () => console.log("API on http://localhost:3000"));
```

Rotalardan önce `app.use()` ile eklenen middleware, bütün `OPTIONS` preflight isteklerini de cevaplar ([Express cors middleware](https://expressjs.com/en/resources/middleware/cors.html)). Origin'leri tarayıcının gönderdiği biçimde, sonda eğik çizgi olmadan yazın. Başka origin'lerden gelen isteklere `Access-Control-Allow-Origin` header'ı dönmez; amaç da budur. `credentials: true` ayarını yalnız ön yüz `credentials: "include"` ile çerez gönderiyorsa bırakın.

Preflight cevabını terminalden kontrol edin:

```bash
curl -i -X OPTIONS http://localhost:3000/api/products \
  -H "Origin: http://localhost:5173" \
  -H "Access-Control-Request-Method: POST" \
  -H "Access-Control-Request-Headers: content-type"
```

Çalıştırmamızdan ilgili satırlar:

```text
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: http://localhost:5173
Vary: Origin
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET,POST,PUT,DELETE
Access-Control-Allow-Headers: Content-Type,Authorization
Access-Control-Max-Age: 600
```

`Vary: Origin`, önbelleklere ve CDN'lere cevabın `Origin` header'ına göre değiştiğini söyler. Aynı komut `Origin: https://evil.example` ile gönderildiğinde yine `204` döner, ama yanıtta `Access-Control-Allow-Origin` satırı bulunmaz.

### Flask

`pip install flask flask-cors` ile kurun.

```python
# app.py: aynı API, Flask 3 ve Flask-CORS 6 ile
from flask import Flask, jsonify, request
from flask_cors import CORS

app = Flask(__name__)
CORS(
    app,
    resources={r"/api/*": {"origins": ["https://app.example.com", "http://localhost:5173"]}},
    allow_headers=["Content-Type", "Authorization"],
    supports_credentials=True,
    max_age=600,
)

@app.get("/api/products")
def list_products():
    return jsonify([{"id": 1, "name": "Desk lamp"}])

@app.post("/api/products")
def create_product():
    return jsonify({"created": request.get_json()}), 201

if __name__ == "__main__":
    app.run(port=5000)
```

Çalıştırmamızda preflight cevabı origin, yöntemler ve `Vary: Origin` ile birlikte `200` döndü, sayfadan gönderilen `POST` ise `201` aldı. `supports_credentials=True` kullanıyorsanız mutlaka bir origin listesi verin: liste olmadan Flask-CORS 6.0.5, gönderdiğimiz rastgele bir origin'i (`https://evil.example`) `Access-Control-Allow-Credentials: true` ile birlikte olduğu gibi geri döndürdü.

### nginx, ağ geçitleri ve CDN'ler

Header'ları uygulama değil de bir ters proxy (reverse proxy) yazıyorsa her `add_header` satırına `always` parametresini koyun; böylece hata yanıtları da bu header'ları taşır. Header'ları yalnız tek bir katman yazsın. Kimlik bilgilerine izin verirken gelen her `Origin` değerini yanıta kopyalamayın: o durumda her web sitesi, kullanıcılarınızın çerezleriyle onların verilerini okuyabilir. Origin'i sabit bir listeyle karşılaştırın.

## Geliştirme ortamı: API'yi geliştirme sunucusu üzerinden yönlendirin

Geliştirme sırasında en kolay çözüm, API'yi aynı origin'e taşımaktır. Vite'ın geliştirme sunucusu `/api` ile başlayan her yolu API'ye iletebilir:

```js
// vite.config.js: geliştirmede /api istekleri Vite üzerinden API'ye gider
import { defineConfig } from "vite";

export default defineConfig({
  server: {
    port: 5173,
    proxy: {
      "/api": {
        target: "http://localhost:3000",
        changeOrigin: true,
      },
    },
  },
});
```

Ön yüz, alan adı yazmadan `fetch("/api/products")` çağırır. Tarayıcı isteğin kendi origin'ine gittiğini gördüğü için CORS kontrolü yapmaz, Vite de isteği 3000 portuna iletir; testimizde `GET` `200`, `POST` `201` döndü. `changeOrigin`, `Host` header'ını hedefin adresine çevirir. webpack-dev-server aynı işi `devServer.proxy` ayarıyla yapar. Canlı ortamda ön yüzü ve API'yi web sunucunuz üzerinden aynı origin'de sunun ya da yukarıdaki CORS ayarını koruyun.

## API sizin değilse: isteği kendi sunucunuzdan yapın

Üçüncü taraf bir API CORS header'ı göndermiyorsa büyük olasılıkla sunucudan çağrılmak için tasarlanmıştır; çoğu zaman bunun nedeni, gizli anahtarının tarayıcıya hiç ulaşmaması gerektiğidir. Kendi backend'inize bir rota ekleyin: tarayıcı sizin origin'inizi çağırır, sizin sunucunuz da API'yi.

```js
// relay.js: üçüncü taraf API'yi backend'iniz çağırır; tarayıcı yalnız sizinle konuşur
import express from "express";

const app = express();
const PARTNER_URL = "https://api.partner.example/v1/products";

app.get("/api/partner-products", async (req, res) => {
  try {
    const r = await fetch(PARTNER_URL, {
      headers: { Authorization: `Bearer ${process.env.PARTNER_API_KEY}` },
      signal: AbortSignal.timeout(10_000),
    });
    res.status(r.status).type(r.headers.get("content-type") ?? "application/json");
    res.send(await r.text());
  } catch (err) {
    res.status(502).json({ error: "partner API unreachable", detail: err.cause?.code ?? err.name });
  }
});

app.listen(8080, () => console.log("relay on http://localhost:8080"));
```

İş ortağı API'sinin yerine CORS header'ı göndermeyen yerel bir test sunucusu koyduk; rota JSON'u `200` ile döndürdü. Rotayı sayfanızla aynı origin'den sunun; anahtar sunucudaki bir ortam değişkeninde kalır. Sunucu tarafında `fetch` ve Axios ile header, istek gövdesi ve kimlik doğrulama kullanımını [JavaScript'te cURL: fetch, Axios ve Proxy](/tr/blog/curl-in-javascript) yazısında anlattık.

Hedef adresi sabit tutun. `?url=` ile gelen her adresi çağıran bir rota, sunucunuzu herkesin kullanabileceği açık bir proxy'ye çevirir; bu proxy, yalnız sunucunuzun erişebildiği iç adreslere bile yönlendirilebilir. API'nin kullanım şartları ve hız sınırları da geçerliliğini korur: çağrının yeri değişti, kurallar değişmedi.

## Herkese açık CORS proxy'leri neden risklidir?

Herkese açık bir CORS proxy'si, bir URL'yi sizin yerinize çağırır ve cevaba `Access-Control-Allow-Origin: *` ekler. Hata kaybolur, ama:

- Servisi işleten kişi tam URL'yi, API anahtarları ve token'lar dahil her header'ı ve yanıtın tamamını görür.
- Yanıtı değiştirebilir, sayfanız da gelen her şeye güvenir.
- Kullanıcılarınızın istekleri, hiçbir sözleşmeniz olmayan bir şirketin üzerinden geçer.
- Servisin hız sınırları ve kesintileri sizin sorununuz olur.

## CORS ve web scraping: Python ya da Node.js betiğiniz bu hatayı neden hiç görmez?

CORS yalnız tarayıcılarda vardır. Tarayıcının engellediği aynı API'yi bu kez Node.js 24'ten çağırdık:

```js
// Aynı istek Node.js'ten: tarayıcı yok, CORS kontrolü yok
const r = await fetch("http://localhost:3001/api/products");
console.log(r.status, r.headers.get("access-control-allow-origin"), await r.text());
```

```text
200 null [{"id":1,"name":"Desk lamp"}]
```

Yanıtta `Access-Control-Allow-Origin` header'ı yok, Node.js yine de okuyor; Python'un Requests kütüphanesi ve curl da aynı şekilde davranır. Veri toplama işini tarayıcı konsolunda ya da bir ön yüz uygulamasında `fetch()` ile yapmaya çalışıyorsanız CORS hatası, bu işin sunucu tarafındaki koda ait olduğunu söylüyordur. Bunun için hangi dilin uygun olduğunu [Web Kazıma: JavaScript mi Python mu?](/tr/blog/web-scraping-javascript-vs-python) yazısında karşılaştırdık. Sitenin kuralları orada da geçerlidir: `robots.txt` kurallarına uyun, istek hızını düşük tutun ve varsa resmî API'yi kullanın.

Proxy, CORS hatasını çözmez. Tarayıcı sayfanın origin'ini `Access-Control-Allow-Origin` header'ıyla karşılaştırır ve IP adresi bu kontrolün parçası değildir; bu yüzden residential proxy, datacenter proxy ya da VPN hiçbir şeyi değiştirmez. Proxy'nin yeri, sunucu tarafındaki kodunuzun HTTP istemcisidir; kurulumunu [Node.js'te Proxy Kullanımı](/tr/blog/nodejs-proxy) yazısında gösterdik.

Birçok ülke ve şehirden yerel sonuç gerektiren, izinli veri toplama işlerinde [Residential Proxy](https://proxynet.io/tr/residential-proxy), istekleri ülke ve şehir hedeflemesiyle ev bağlantıları üzerinden gönderir.

Herkese açık API'lere ve sıkı korunmayan sayfalara yüksek hacimli istekler için [Datacenter Proxy](https://proxynet.io/tr/datacenter-proxy), size ayrılmış IPv4 adreslerini trafik sınırı olmadan sunar.

## CORS hatasıyla kimler karşılaşır?

- Uygulaması ve API'si farklı portlarda çalışan ön yüz geliştiricileri.
- Üçüncü taraf bir API'yi doğrudan tarayıcıdan çağıran tek sayfalık uygulamalar.
- API'sini `api.example.com` gibi bir alt alan adına ya da `https` adresine taşıyan ekipler.
- Yapay zekâ araçlarıyla üretilen ve API'yi doğrudan, kimi zaman anahtarı sayfaya gömerek çağıran ön yüzler.

## Sık yapılan hatalar

- **`Access-Control-Allow-Origin` header'ını isteğe eklemek.** Bu bir yanıt header'ıdır; `fetch()` içinde özel bir header'a dönüşür ve preflight'ı tetikler.
- **`mode: "no-cors"` kullanmak.** Yanıt opak (opaque) gelir: durum kodu `0`, gövde okunamaz.
- **"Allow CORS" eklentisi kurmak ya da web güvenliğini kapatmak.** Yalnız sizin tarayıcınızı değiştirir; üstelik böyle bir eklenti çalıştığı sayfaları okuyabilir.
- **Ön yüz çerez gönderirken `*` ile cevap vermek.** Tarayıcı bu ikiliyi reddeder.
- **Express 5'te `app.options("*", cors())` yazmak.** Uygulama açılışta `PathError [TypeError]: Missing parameter name at index 1: *` hatasıyla durur; `app.use(cors())` preflight isteklerini zaten cevaplar.
- **`OPTIONS` isteklerini kimlik doğrulamada reddetmek.** Preflight istekleri token taşımaz, bu yüzden "It does not have HTTP ok status" hatasıyla düşer.

## Karar rehberi

| Durum | Ne yapmalı |
|---|---|
| Geliştirmede ön yüz ve API farklı portlarda | Geliştirme sunucusunun proxy'si (Vite'ta `server.proxy`) |
| Kendi API'niz, kendi ön yüzünüzden çağrılıyor | Tam origin'lere izin verin; `OPTIONS` isteğini cevaplayın |
| Ön yüz çerez gönderiyor | Tam origin, `Access-Control-Allow-Credentials: true`, `Vary: Origin` |
| Bir header ya da yöntem "is not allowed" | `Access-Control-Allow-Headers` ya da `-Methods` listesine ekleyin |
| Hata bir dağıtımdan sonra ya da yük altında çıkıyor | Gerçek durum kodunu curl ile kontrol edin; nginx'te `always` |
| CORS header'ı göndermeyen üçüncü taraf API | Kendi sunucunuzdan çağırın, anahtar sunucuda kalsın |
| Başka sitelerden veri toplamak | Sunucu tarafında kod; orada CORS uygulanmaz |

## Sıkça sorulan sorular

### Postman ya da curl çalışıyor, tarayıcı neden CORS hatası veriyor?

CORS'u yalnız tarayıcılar uygular. Sunucu her istemciye aynı yanıtı gönderir; yanıtı bir betiğe vermeden önce `Access-Control-Allow-Origin` header'ına yalnız tarayıcı bakar. Çalışan bir curl çağrısı API'nin çalıştığını gösterir, tarayıcının yanıtı okuyabileceğini değil.

### Localhost'ta neden CORS hatası alıyorum?

Farklı port, farklı origin demektir: `localhost:5173` ile `localhost:3000` aynı bilgisayarda çalışsa da iki ayrı origin'dir. API'de ön yüzün origin'ine izin verin ya da geliştirme sunucusunun proxy'sini kullanın. Bundan bağımsız olarak Chrome 142'den bu yana, `localhost` adresini ya da ev ağınızdaki bir cihazı çağıran herkese açık bir web sitesi önce sizden izin ister; reddederseniz konsol, `loopback` ya da `local` adres alanı için iznin reddedildiğini yazar.

### mode: "no-cors" CORS hatasını çözer mi?

Hayır. İstek gönderilir, ama tarayıcı opak bir yanıt döndürür; testimizde durum kodu `0`, türü `opaque` oldu ve gövde okunamadı. Yalnız cevabını hiç okumayacağınız istekler için uygundur.

### CORS, API'm için bir güvenlik önlemi mi?

Hayır. CORS, bir sitenin ziyaretçinin çerezleriyle başka bir sitedeki verileri okumasını engeller; ama herkes API'nizi bir betikle çağırmaya devam edebilir. API'yi kimlik doğrulama, yetkilendirme ve hız sınırlarıyla koruyun.

### Proxy ya da VPN CORS hatasını çözer mi?

Hayır. Tarayıcı sayfanın origin'ini yanıttaki `Access-Control-Allow-Origin` header'ıyla karşılaştırır; IP adresi bu kontrolün parçası değildir.

### Neden yalnız POST isteğim hata veriyor da GET çalışıyor?

`POST` isteğiniz büyük olasılıkla JSON gövdesi, `Authorization` header'ı ya da özel bir header yüzünden preflight gerektiriyor. API `OPTIONS` isteğini doğru cevaplamazsa tarayıcı `POST` isteğini hiç göndermez. Network sekmesinde `OPTIONS` kaydına bakın ya da preflight'ı curl ile gönderin.

## Özet

CORS hatası, tarayıcının başka bir origin'den gelen yanıtı betiğinize vermemesidir; istek çoğu zaman sunucuya ulaşmıştır. Nedeni konsolda okuyun, gerçek durum kodunu curl ile kontrol edin ve sorunu sunucuda çözün: tam origin'ler, `OPTIONS` isteğine bir cevap, doğru yöntemler ve header'lar, `Vary: Origin`. Yerel çalışırken geliştirme sunucusunun proxy'sini, size ait olmayan API'ler için kendi sunucunuzu kullanın. Veri toplama işi, CORS'un uygulanmadığı sunucu tarafındaki koda aittir; bu iş için kullanabileceğiniz proxy türleri [proxy hizmetlerimiz](/tr/proxy) sayfasında.
