Next.js CORS 에러 완전 정복 — 원인부터 해결까지
Next.js로 프로젝트를 만들다 보면 외부 API를 호출하는 순간 브라우저 콘솔에 이런 메시지가 뜨는 경우가 많습니다.
Access to fetch at 'https://api.example.com/data' from origin 'http://localhost:3000'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present.
이 글에서는 CORS가 왜 생기는지, Next.js에서 어떻게 해결하는지를 단계별로 설명합니다.
CORS가 뭔가요?
CORS(Cross-Origin Resource Sharing)는 브라우저의 보안 정책입니다. 브라우저는 기본적으로 다른 출처(도메인, 포트, 프로토콜)의 서버로 요청을 보낼 때 서버의 허락을 요구합니다. 서버가 "이 출처는 허용한다"는 응답 헤더를 보내지 않으면 브라우저가 요청 자체를 막아버립니다.
중요: CORS는 서버가 막는 게 아니라 브라우저가 막습니다. 같은 요청을 curl로 보내면 잘 됩니다.
Next.js에서 CORS 에러가 나는 흔한 상황
- 클라이언트(브라우저)에서 직접 외부 API 호출
- Next.js API Routes에 다른 도메인에서 요청
- 개발 환경(
localhost:3000)에서 프로덕션 API 호출
해결 방법 1: Next.js API Route를 프록시로 사용 (추천)
외부 API를 직접 브라우저에서 호출하지 말고, Next.js API Route를 거쳐서 호출하면 CORS 문제가 없어집니다. 서버끼리의 통신은 CORS 제한을 받지 않기 때문입니다.
App Router 방식 (app/api/data/route.ts)
export async function GET() {
const res = await fetch('https://api.example.com/data', {
headers: { 'Authorization': `Bearer ${process.env.API_KEY}` },
});
const data = await res.json();
return Response.json(data);
}
이제 클라이언트에서는 외부 API 대신 /api/data를 호출하면 됩니다.
해결 방법 2: next.config.js의 rewrites 사용
코드 변경 없이 설정만으로 프록시를 만들 수 있습니다.
// next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/api/external/:path*',
destination: 'https://api.example.com/:path*',
},
];
},
};
이 설정 후 클라이언트에서 /api/external/data를 호출하면 Next.js 서버가 https://api.example.com/data로 대신 요청합니다.
해결 방법 3: 내 API Route에 CORS 헤더 추가
다른 도메인에서 내 Next.js API Route를 호출해야 하는 경우라면, 응답에 CORS 헤더를 추가해야 합니다.
// app/api/myroute/route.ts
export async function GET(request: Request) {
return new Response(JSON.stringify({ message: 'ok' }), {
headers: {
'Access-Control-Allow-Origin': 'https://my-frontend.com',
'Content-Type': 'application/json',
},
});
}
export async function OPTIONS() {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': 'https://my-frontend.com',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
});
}
하지 말아야 할 것: Access-Control-Allow-Origin: *
모든 출처를 허용하는 와일드카드(*)는 편해 보이지만, 인증(쿠키, Authorization 헤더)과 함께 사용할 수 없고 보안 취약점이 생길 수 있습니다. 특히 프로덕션에서는 필요한 도메인만 명시적으로 허용하세요.
자주 하는 실수
- 환경 변수를 클라이언트에 노출:
NEXT_PUBLIC_이 붙은 변수는 브라우저에서도 보입니다. API 키는NEXT_PUBLIC_없이 서버에서만 사용하세요. - 개발 환경에서만 동작 확인: 개발 서버와 프로덕션 서버의 도메인이 다르므로, 배포 후에도 CORS 설정을 확인하세요.
- OPTIONS preflight 누락: POST 요청 전에 브라우저는 OPTIONS 요청을 먼저 보냅니다. OPTIONS 핸들러가 없으면 CORS 에러가 납니다.
정리
Next.js에서 CORS 문제를 만났을 때 가장 먼저 시도할 방법은 API Route를 프록시로 활용하는 것입니다. 외부 API 키를 서버에서 관리할 수 있어 보안에도 좋습니다. 설정만으로 해결하고 싶다면 rewrites를 사용하세요.
원인을 파악하기 어렵거나 여러 방법을 시도해도 계속 에러가 난다면, 상황을 정리해서 알려주시면 같이 살펴보겠습니다.