CORS (Cross-Origin Resource Sharing) adalah aturan yang dipakai browser buat memutuskan apakah JavaScript di satu situs boleh membaca jawaban dari server di origin lain. Server yang memberi izin lewat header, browser yang menjaga aturannya. Kalau kamu pernah lihat error merah "blocked by CORS policy" di console, ini penjelasannya.
🧪 Tebakan cepat: halaman di
https://app.commemanggilhttps://app.com:8080/data. Dua alamat itu satu origin atau beda? Tebak dulu, jawabannya ada di bagian "Origin: skema, host, port".
Origin: skema, host, port
Origin adalah tiga bagian depan sebuah alamat. Path dan query di belakangnya gak dihitung:
https://app.com:443/profil?tab=1
skema https
host app.com
port 443 (https tanpa port tertulis = 443, http = 80)
path /profil?tab=1 bukan bagian origin
Dua alamat satu origin cuma kalau ketiga bagiannya sama persis. Dibandingkan dengan https://app.com:
| Alamat | Origin | Kenapa |
|---|---|---|
https://app.com/profil |
sama | path gak dihitung |
http://app.com |
beda | skemanya http |
https://api.app.com |
beda | host-nya lain, subdomain juga dihitung |
https://app.com:8080 |
beda | port-nya 8080, bukan 443 |
Baris terakhir menjawab tebakannya: beda origin.
Browser punya aturan bawaan bernama Same-Origin Policy: JavaScript boleh membaca jawaban dari origin-nya sendiri, tapi gak boleh membaca jawaban dari origin lain, kecuali server di origin itu mengizinkannya. CORS adalah cara server memberi izin itu.
Izin lewat Access-Control-Allow-Origin
Waktu JavaScript di https://app.com menjalankan fetch("https://api.com/data"), browser menambahkan header Origin sendiri:
GET /data HTTP/1.1
Host: api.com
Origin: https://app.com
Server menjawab. Yang menentukan nasibnya satu header ini:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://app.com
Content-Type: application/json
- Kalau
Access-Control-Allow-Originberisi origin halamannya (atau*, artinya semua origin), browser menyerahkan jawabannya ke JavaScript. - Kalau header itu gak ada, atau isinya origin lain, browser menahan jawabannya dan menulis error CORS di console.
Perhatikan: di kasus kedua, request-nya sudah sampai dan server sudah memprosesnya. Yang diblokir browser cuma JavaScript yang mau membaca jawabannya.
Preflight: minta izin dulu dengan OPTIONS
Request sederhana langsung dikirim. Sederhana artinya method-nya GET, HEAD atau POST, tanpa header tambahan kayak Authorization, dan Content-Type-nya cuma text/plain, multipart/form-data atau application/x-www-form-urlencoded (format form biasa).
Selain itu, misalnya PUT, DELETE, header Authorization, atau Content-Type: application/json, browser bertanya dulu lewat request OPTIONS. Request ini disebut preflight:
OPTIONS /data HTTP/1.1
Origin: https://app.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: authorization
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.com
Access-Control-Allow-Methods: GET, POST, DELETE
Access-Control-Allow-Headers: Authorization
Access-Control-Max-Age: 600
Kalau jawaban preflight mengizinkan origin, method dan header-nya, browser baru mengirim request DELETE yang asli. Kalau gak, request aslinya gak pernah dikirim. Access-Control-Max-Age: 600 artinya browser boleh mengingat izin ini 600 detik, jadi gak perlu preflight lagi tiap kali.
Browser yang menjaga, bukan server
- CORS cuma ada di browser. Request dari server ke server (PHP, Node, curl, Postman) gak kena CORS sama sekali.
- Error CORS diperbaiki di server tujuan, dengan menambah header izin. Kode
fetchdi frontend gak bisa memberi izin buat dirinya sendiri. - CORS bukan pengaman API. Dia cuma mengatur halaman mana yang boleh membaca jawaban di browser, jadi API tetap butuh login atau token.
⚠️ Jebakan yang sering ketemu
localhost:5173memanggillocalhost:8000. Port beda berarti origin beda, jadi frontend di dev server yang memanggil API lokal juga butuh izin CORS.*bareng cookie. Kalaufetchmembawa cookie (credentials: "include"),Access-Control-Allow-Origin: *gak berlaku. Tulis origin-nya persis dan tambahkanAccess-Control-Allow-Credentials: true.- Mengira
mode: "no-cors"memperbaiki error. Error-nya memang hilang, tapi jawabannya jadi kosong dan JavaScript tetap gak bisa membacanya. - Server gak menjawab
OPTIONS. Kalau preflight dapat 404 atau jawabannya tanpa header izin, request aslinya gak pernah dikirim.
TL;DR: Origin adalah skema, host dan port sebuah alamat, dan beda satu bagian saja sudah beda origin. Browser melarang JavaScript membaca jawaban dari origin lain, kecuali server menjawab dengan Access-Control-Allow-Origin berisi origin halamannya. Untuk request yang gak sederhana (PUT, DELETE, header Authorization, body JSON), browser mengirim preflight OPTIONS dulu dan baru lanjut kalau diizinkan. CORS dijaga browser dan diperbaiki di server, dan request dari server ke server gak kena CORS.