CORS: Kenapa Browser Menolak Permintaan dan Cara Men-debug-nya
Pernahkah Anda melihat pesan merah yang mengerikan di konsol browser seperti ini: Access to fetch at 'http://api.example.com/data' from origin 'http://localhost:3000' has been blocked by CORS policy?
Bagi banyak developer, CORS (Cross-Origin Resource Sharing) terasa seperti “musuh” yang muncul secara acak dan menghalangi aplikasi mereka untuk mengambil data dari API. Namun, CORS sebenarnya adalah mekanisme keamanan krusial yang diimplementasikan oleh browser untuk melindungi pengguna dari serangan berbahaya.
Artikel ini akan mengupas tuntas mekanisme CORS, kapan browser melakukan “Preflight”, dan bagaimana cara men-debug-nya tanpa harus menebak-nebak.
Ringkasan
- CORS adalah kebijakan keamanan di sisi browser, bukan di sisi server.
- Server tidak “menolak” permintaan; server mengirim respon, tetapi browser-lah yang memutuskan apakah aplikasi JavaScript boleh membaca respon tersebut.
- Simple Request: Permintaan yang langsung dikirim ke server (misal: GET dengan header standar).
- Preflight Request: Permintaan
OPTIONSyang dikirim browser sebelum permintaan asli untuk memastikan server mengizinkan metode atau header tertentu. - Solusi utama adalah konfigurasi header
Access-Control-Allow-Originyang tepat di server. - Penggunaan Proxy (seperti Nginx atau middleware) adalah solusi umum untuk menghindari masalah CORS selama pengembangan.
Apa itu “Origin”?
Sebelum memahami CORS, kita harus memahami konsep Origin. Sebuah origin didefinisikan oleh tiga komponen:
- Protokol (http vs https)
- Domain/Host (example.com vs api.example.com)
- Port (80 vs 3000)
Jika salah satu dari ketiga hal ini berbeda antara halaman web yang memuat script dan server yang dipanggil, maka permintaan tersebut disebut Cross-Origin.
Contoh:
http://localhost:3000$\rightarrow$http://localhost:3000/api(Same-Origin)http://localhost:3000$\rightarrow$https://localhost:3000/api(Cross-Origin - beda protokol)http://localhost:3000$\rightarrow$http://localhost:8080/api(Cross-Origin - beda port)http://app.com$\rightarrow$http://api.app.com(Cross-Origin - beda subdomain)
Cara Kerja CORS
Saat aplikasi JavaScript melakukan fetch ke origin yang berbeda, browser akan melakukan salah satu dari dua skenario berikut: Simple Request atau Preflight Request.
1. Simple Request
Browser mengirim permintaan langsung ke server. Permintaan ini dikategorikan sebagai “Simple” jika memenuhi syarat:
- Metode HTTP adalah
GET,HEAD, atauPOST. - Header yang digunakan hanya header standar (seperti
Accept,Accept-Language,Content-Language). - Jika
POST,Content-Typeharus salah satu dari:application/x-www-form-urlencoded,multipart/form-data, atautext/plain.
Prosesnya:
- Browser mengirim request ke server.
- Server memproses request dan mengirim respon beserta header
Access-Control-Allow-Origin. - Browser memeriksa header tersebut. Jika header tersebut tidak ada atau tidak cocok dengan origin pengirim, browser akan memblokir respon dan memunculkan error CORS di konsol, meskipun server sebenarnya sudah mengirim data (status 200 OK).
2. Preflight Request (The OPTIONS Request)
Jika permintaan tidak memenuhi syarat “Simple” (misal: menggunakan PUT, DELETE, atau mengirim Content-Type: application/json), browser akan merasa permintaan ini “berbahaya” bagi server yang tidak mendukung CORS.
Untuk mencegah kerusakan data, browser mengirim Preflight Request terlebih dahulu.
Urutan Kejadian:
- OPTIONS Request: Browser mengirim request dengan metode
OPTIONSke endpoint tujuan.- Header
Origin: Menginfokan siapa yang memanggil. - Header
Access-Control-Request-Method: “Bolehkah saya menggunakan metode POST?” - Header
Access-Control-Request-Headers: “Bolehkah saya mengirim header Authorization?”
- Header
- Server Response: Server harus menjawab dengan status 200 atau 204 dan header:
Access-Control-Allow-Origin: Mengizinkan origin tersebut.Access-Control-Allow-Methods: Daftar metode yang diizinkan (misal:GET, POST, OPTIONS).Access-Control-Allow-Headers: Daftar header yang diizinkan.
- Actual Request: Jika respon preflight sukses, browser baru akan mengirimkan permintaan asli (misal:
POSTdengan body JSON).
Jika preflight gagal, browser tidak akan pernah mengirim permintaan asli, dan Anda akan melihat error CORS di konsol.
Strategi Perbaikan (The Fix)
Solusi A: Konfigurasi Server (Cara Benar)
Cara paling tepat adalah mengonfigurasi server untuk mengizinkan origin tertentu. Jangan pernah menggunakan Access-Control-Allow-Origin: * di lingkungan produksi kecuali API Anda benar-benar publik.
Contoh implementasi logika server:
- Baca header
Origindari request. - Cek apakah origin tersebut ada dalam daftar putih (whitelist).
- Jika ya, set header
Access-Control-Allow-Origindengan nilai origin tersebut.
Menurut MDN Web Docs on CORS, konfigurasi yang tepat memastikan bahwa hanya aplikasi tepercaya yang dapat mengakses data sensitif.
Solusi B: Menggunakan Proxy (Cara Development)
Selama pengembangan, seringkali kita tidak punya akses ke server API atau malas mengonfigurasi CORS. Solusinya adalah menggunakan proxy.
Konsep Proxy: Browser $\rightarrow$ Local Proxy (Same-Origin) $\rightarrow$ Remote API (Server-to-Server)
Karena CORS adalah kebijakan browser, permintaan dari server (Proxy) ke server lain (API) tidak terikat aturan CORS.
Jika Anda menggunakan Vite atau Webpack, Anda bisa menambahkan konfigurasi proxy di vite.config.js:
server: {
proxy: {
'/api': {
target: 'http://api.example.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}Perbandingan: Simple vs Preflight Request
Untuk memudahkan pemahaman, berikut adalah perbandingan antara kedua jenis permintaan CORS:
| Fitur | Simple Request | Preflight Request |
|---|---|---|
| Metode HTTP | GET, HEAD, POST | PUT, DELETE, PATCH, atau POST (JSON) |
| Header | Hanya header standar | Custom header (misal: Authorization) |
| Alur | Langsung ke server | OPTIONS $\rightarrow$ Request Asli |
| Respon Server | Access-Control-Allow-Origin | Allow-Origin, Allow-Methods, Allow-Headers |
| Risiko Server | Rendah (standar HTTP) | Tinggi (bisa mengubah state/data) |
Men-debug CORS dengan DevTools
Jangan hanya melihat pesan error di konsol. Gunakan tab Network di Chrome/Firefox DevTools:
- Cari Request OPTIONS: Jika Anda melihat request
OPTIONSdengan status merah, berarti preflight gagal. Periksa tab “Response Headers” untuk melihat apa yang dikirim server. - Periksa Header
Origin: Pastikan headerOriginyang dikirim browser benar-benar sama dengan yang diharapkan server. - Cek Status Code: Ingat, CORS error bisa terjadi meskipun status code adalah
200 OK. Yang menentukan adalah ada atau tidaknya headerAccess-Control-Allow-Origin.
Kesimpulan
CORS bukan bug, melainkan fitur keamanan yang melindungi pengguna dari serangan seperti Cross-Site Request Forgery (CSRF) pada tingkat dasar. Dengan memahami perbedaan antara Simple Request dan Preflight, Anda bisa menentukan apakah masalah Anda terletak pada konfigurasi metode HTTP, header yang tidak dikenal, atau sekadar salah konfigurasi origin di server.
Untuk referensi lebih mendalam, Anda dapat mempelajari:
Fetch Standard dari WHATWG yang mendefinisikan bagaimana browser menangani permintaan jaringan secara detail.
RFC 6454 yang merupakan spesifikasi dasar dari CORS.
MDN CORS Guide untuk panduan implementasi praktis.
Gunakan
Originyang spesifik, hindari*untuk data sensitif.Selalu tangani metode
OPTIONSdi backend jika Anda menggunakan JSON atau custom headers.Manfaatkan proxy selama development untuk mempercepat workflow.
Baca tab Network di DevTools untuk melihat apakah preflight (OPTIONS) terkirim atau tidak.