## 들어가며
웹 개발을 하다 보면 CORS(Cross-Origin Resource Sharing) 오류와 마주치게 됩니다. 특히 프론트엔드에서 외부 API를 호출할 때 자주 발생하는 이 문제는 많은 개발자들을 괴롭히곤 합니다. 그런데 Next.js를 사용하면 이런 CORS 문제를 우아하게 해결할 수 있습니다. 이 글에서는 Next.js의 API 라우트가 어떻게 CORS 문제를 해결하고, 웹서버와 WAS(Web Application Server)가 어떻게 동일한 출처에서 공존하는지 알아보겠습니다.
## CORS란 무엇인가?
CORS는 '교차 출처 리소스 공유'라는 의미로, 웹 브라우저에서 실행 중인 스크립트가 다른 출처(Origin)의 리소스에 접근할 때 적용되는 보안 메커니즘입니다.
### 출처(Origin)란?
출처는 프로토콜(http/https), 도메인, 포트의 조합을 의미합니다. 예를 들어 `https://example.com:443`은 하나의 출처입니다.
### CORS 오류가 발생하는 이유
브라우저는 보안상의 이유로 '동일 출처 정책(Same-Origin Policy)'을 적용합니다. 이 정책에 따라 웹 페이지는 기본적으로 같은 출처의 리소스만 요청할 수 있습니다. 다른 출처의 리소스를 요청하려면 해당 서버가 적절한 CORS 헤더를 응답에 포함시켜야 합니다.
예를 들어, `https://myapp.com`에서 실행 중인 JavaScript가 `https://api.example.com`의 데이터를 요청하면 브라우저는 이를 교차 출처 요청으로 간주하고, `api.example.com` 서버가 적절한 CORS 헤더를 제공하지 않으면 요청을 차단합니다.
## 브라우저에서 직접 API 요청 vs Next.js 서버를 통한 요청
### 브라우저에서 직접 API 요청 시 CORS 발생
```
브라우저(myapp.com) → API 서버(api.example.com)
```
이 경우 출처가 다르기 때문에 API 서버가 적절한 CORS 헤더를 제공하지 않으면 브라우저는 요청을 차단합니다.
### Next.js 서버를 통한 API 요청 시 CORS 우회
```
브라우저(myapp.com) → Next.js 서버(myapp.com/api) → API 서버(api.example.com)
```
이 방식에서는 브라우저가 동일 출처인 Next.js 서버로 요청을 보내고, Next.js 서버가 API 서버로 요청을 대신 전달합니다. 서버 간 통신에는 브라우저의 CORS 제한이 적용되지 않기 때문에 CORS 오류가 발생하지 않습니다.
## Next.js의 통합 서버 아키텍처
Next.js의 가장 큰 특징 중 하나는 프론트엔드와 백엔드 코드를 하나의 프로젝트에서 관리할 수 있다는 점입니다. 이는 Next.js 서버가 웹서버와 WAS의 역할을 동시에 수행하기 때문에 가능합니다.
### Next.js 서버의 이중 역할
1. **웹서버 역할**: 정적 파일 제공 및 React 페이지 렌더링
```javascript
// pages/index.js
export default function Home() {
return <h1>Hello World</h1>;
}
```
2. **WAS(백엔드) 역할**: API 요청 처리
```javascript
// pages/api/example.js
export default function handler(req, res) {
res.status(200).json({ message: '이것은 API 응답입니다' });
}
```
### 라우팅 기반 분리
Next.js 서버는 요청 경로에 따라 적절한 핸들러로 라우팅합니다:
- `/api/*` 경로로 들어오는 요청 → API 핸들러로 라우팅 (WAS 기능)
- 그 외 경로로 들어오는 요청 → 페이지 컴포넌트 렌더링 (웹서버 기능)
## 로컬 개발 환경과 배포 환경에서의 작동 방식
### 로컬 개발 환경 (`npm run dev`)
로컬에서 Next.js 개발 서버를 실행하면 `localhost:3000`에서 웹서버와 WAS 기능이 모두 제공됩니다. 브라우저에서 `localhost:3000/api/some-endpoint`로 요청을 보내면, 이는 동일 출처로 간주되어 CORS 문제가 발생하지 않습니다.
### 배포 환경 (Vercel 등)
Vercel과 같은 서비스에 Next.js 프로젝트를 배포하면:
1. 정적 파일과 SSR/ISR 페이지를 처리하는 프론트엔드 부분
2. `/api` 디렉토리의 API 라우트를 처리하는 백엔드 부분
이 두 부분이 모두 배포되어 동일한 도메인에서 서비스됩니다. 예를 들어 `your-app.vercel.app`에 배포된 경우, 브라우저에서 `your-app.vercel.app/api/data`로 API 요청을 보내면 동일 출처이므로 CORS 문제가 발생하지 않습니다.
## 서버 간 통신 제한 방법
공개 API라도 서버 간 통신을 제한해야 할 때가 있습니다. 이를 위한 몇 가지 방법을 살펴보겠습니다:
### 1. 인증 메커니즘 구현
API 키나 토큰을 요구하여 인증된 요청만 허용합니다.
```javascript
// Next.js 서버에서 API 요청 시
const response = await fetch('https://api.example.com/data', {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
}
});
```
### 2. 출처 확인 메커니즘
서버에서 요청의 출처(Referer/Origin 헤더)를 확인합니다.
```javascript
// API 서버 측 코드 (예: Express)
app.use((req, res, next) => {
const allowedOrigins = ['https://trusted-server.com'];
const origin = req.headers.origin || req.headers.referer;
if (!allowedOrigins.includes(origin)) {
return res.status(403).json({ error: '허용되지 않은 출처' });
}
next();
});
```
### 3. IP 기반 제한
특정 IP 주소에서만 API 접근을 허용합니다.
### 4. 요청 속도 제한 (Rate Limiting)
특정 시간 내 허용되는 요청 수를 제한합니다.
### 5. 상호 TLS (mTLS)
클라이언트와 서버 모두 인증서를 사용하여 양방향 인증을 구현합니다.
### 6. 서명된 요청 (Request Signing)
요청 내용을 비밀 키로 서명하여 요청의 무결성과 출처를 보장합니다.
## 결론
Next.js는 웹서버와 WAS의 기능을 하나의 서버에 통합함으로써 CORS 문제를 우아하게 해결합니다. 이 통합 아키텍처 덕분에 프론트엔드와 백엔드 코드가 동일한 프로젝트에 공존하면서도, 동일한 출처에서 서비스될 수 있어 CORS 문제 없이 API 통신이 가능합니다.
Next.js 서버는 요청 경로에 따라 정적 데이터를 반환할지, API 응답을 반환할지 결정합니다. 이러한 구조는 개발 편의성과 배포 효율성을 모두 제공하며, 현대적인 웹 애플리케이션 개발에 큰 장점이 됩니다.
서버 간 통신을 제한해야 할 경우에는 인증, 출처 확인, IP 제한 등 다양한 보안 메커니즘을 활용할 수 있습니다. 이를 통해 API의 보안을 강화하고 무단 접근을 방지할 수 있습니다.
Next.js의 이러한 특성을 이해하고 활용한다면, 더 효율적이고 안전한 웹 애플리케이션을 개발할 수 있을 것입니다.
'프론트엔드 > Next.js' 카테고리의 다른 글
[Next.js] 커스텀 도메인 연결 (0) | 2025.07.26 |
---|---|
[Next.js] 다이나믹(동적) 라우팅 예시 코드 (0) | 2025.07.21 |
[Next.js] Next.js + Typescript 환경에서 카카오 JS SDK 사용하기 (1) | 2025.05.08 |
[Next.js] 다이나믹 임포트를 활용한 하이드레이션 오류 해결방법 | Error: Hydration failed because the server rendered HTML didn't match the client. (0) | 2025.04.30 |
[Next.js] <Image/> 태그 사용방법 (이미지 원본 비율 유지하기 & 부모 요소 너비 꽉 채우기) (0) | 2025.04.21 |