CORS Error: Penyebab, Cara Fix, dan Cara Mencegahnya Selamanya
CORS Error: Penyebab, Cara Fix, dan Cara Mencegahnya Selamanya
Kamu baru saja selesai bikin frontend React yang memanggil API backend. Buka browser, cek console — dan langsung disambut pesan merah yang menyebalkan:
Access to fetch at 'http://localhost:3001/api/users' from origin
'http://localhost:3000' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
CORS error adalah salah satu error paling sering dialami developer web, terutama yang baru mulai memisahkan frontend dan backend. Kabar baiknya: begitu kamu paham cara kerjanya, kamu tidak akan bingung lagi.
1. Apa Itu CORS dan Kenapa Browser Memblokir Request?
CORS (Cross-Origin Resource Sharing) adalah mekanisme keamanan browser yang membatasi halaman web untuk membuat request ke domain yang berbeda dari tempat halaman itu dimuat.
Origin terdiri dari tiga komponen: protokol + domain + port. Jika salah satu berbeda, itu dianggap cross-origin:
http://localhost:3000 → http://localhost:3001 ❌ port berbeda
http://localhost:3000 → https://localhost:3000 ❌ protokol berbeda
http://localhost:3000 → http://myapi.com ❌ domain berbeda
http://localhost:3000 → http://localhost:3000 ✅ sama persis
Penting: CORS adalah kebijakan browser, bukan server. Server tetap menerima dan memproses request — browser yang memblokir response-nya dari JavaScript. Itulah kenapa request dari Postman atau curl selalu berhasil meski CORS belum dikonfigurasi.
2. Fix CORS di Berbagai Backend
Node.js + Express
// Install: npm install cors
import cors from 'cors';
// ✅ Development: izinkan semua origin (JANGAN di production!)
app.use(cors());
// ✅ Production: izinkan origin spesifik
app.use(cors({
origin: [
'https://aplikasikita.com',
'https://www.aplikasikita.com',
],
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true, // Wajib jika pakai cookies atau Authorization header
}));
// ✅ Dynamic origin (untuk multi-tenant atau staging environment)
const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',') || [];
app.use(cors({
origin: (origin, callback) => {
// Izinkan request tanpa origin (Postman, server-to-server)
if (!origin) return callback(null, true);
if (allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error(`Origin ${origin} tidak diizinkan`));
}
},
credentials: true,
}));
Python + FastAPI
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["https://aplikasikita.com"], # atau ["*"] untuk dev
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
Python + Django
# Install: pip install django-cors-headers
# settings.py
INSTALLED_APPS = [
...
'corsheaders',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', # Harus di atas CommonMiddleware!
'django.middleware.common.CommonMiddleware',
...
]
# Development
CORS_ALLOW_ALL_ORIGINS = True
# Production
CORS_ALLOWED_ORIGINS = [
"https://aplikasikita.com",
"https://www.aplikasikita.com",
]
CORS_ALLOW_CREDENTIALS = True
Nginx (Reverse Proxy)
# nginx.conf
server {
location /api/ {
# Handle preflight OPTIONS request
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://aplikasikita.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type';
add_header 'Access-Control-Max-Age' 86400;
return 204;
}
add_header 'Access-Control-Allow-Origin' 'https://aplikasikita.com' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
proxy_pass http://backend:3001;
}
}
3. Kasus Khusus yang Sering Bikin Bingung
Kasus 1: CORS sudah dikonfigurasi tapi masih error
// Masalah paling umum: credentials: true di frontend tapi
// backend tidak set Access-Control-Allow-Credentials
// Frontend (fetch)
fetch('https://api.aplikasikita.com/users', {
credentials: 'include', // Kirim cookies
});
// Backend HARUS set dua hal ini bersamaan:
// 1. Access-Control-Allow-Credentials: true
// 2. Access-Control-Allow-Origin: TIDAK BOLEH pakai wildcard "*"
// Harus origin spesifik!
// ❌ Ini tidak akan bekerja dengan credentials:
app.use(cors({ origin: '*', credentials: true }));
// ✅ Ini yang benar:
app.use(cors({ origin: 'https://aplikasikita.com', credentials: true }));
Kasus 2: Error hanya di preflight (OPTIONS request)
// Browser mengirim OPTIONS request dulu untuk "custom headers"
// seperti Authorization, Content-Type: application/json, dll.
// Pastikan backend handle OPTIONS method:
app.options('*', cors()); // Enable pre-flight untuk semua routes
app.use(cors(corsOptions));
Kasus 3: Development dengan Vite/CRA
// Solusi terbaik untuk development: gunakan proxy di frontend
// Ini menghindari CORS sama sekali karena request dikirim dari server yang sama
// vite.config.ts
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://localhost:3001',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
},
});
// Sekarang fetch('/api/users') akan di-proxy ke http://localhost:3001/users
// Tidak ada CORS error karena origin-nya sama
4. Checklist Debug CORS
| Cek | Cara Verifikasi |
|---|---|
Header Access-Control-Allow-Origin ada di response? | DevTools → Network → klik request → Response Headers |
| Origin di header cocok dengan origin frontend? | Bandingkan nilai header dengan URL frontend |
Jika pakai credentials, origin bukan wildcard *? | Cek nilai header, tidak boleh * |
| OPTIONS preflight berhasil (status 200/204)? | DevTools → Network → filter "OPTIONS" |
Method yang dipakai ada di Allow-Methods? | Cek header Access-Control-Allow-Methods |
Custom header ada di Allow-Headers? | Cek header Access-Control-Allow-Headers |
Kesimpulan
CORS error terlihat menakutkan tapi solusinya selalu ada di satu tempat: konfigurasi header di backend. Ingat tiga aturan utama: (1) set Access-Control-Allow-Origin ke origin yang spesifik, (2) jika pakai credentials jangan pakai wildcard, (3) handle OPTIONS preflight request. Dengan tiga aturan ini, kamu tidak akan pernah bingung dengan CORS lagi.