왜 localhost에서 여전히 CORS 에러가 발생할까
프론트엔드를 localhost:3000에서 실행합니다. 백엔드를 localhost:5000에서 실행합니다. 두 앱 모두 당신의 노트북에서 실행 중입니다. 그런데도 CORS 에러가 발생합니다.
이는 브라우저가 Origin(출처)을 정의하는 방식 때문에 발생합니다.
Origin은 세 가지 부분으로 구성됩니다:
- 프로토콜 (Protocol)
- 도메인 (Domain)
- 포트 (Port)
다음 두 가지를 비교해 보세요:
두 주소는 동일한 프로토콜을 사용합니다. 두 주소는 동일한 도메인을 사용합니다. 하지만 서로 다른 포트를 사용합니다.
브라우저는 포트가 다르면 서로 다른 Origin으로 간주합니다.
React 앱이 API를 호출할 때, 브라우저는 이를 교차 출처(cross-origin) 요청으로 인식합니다. 즉, 두 앱을 별개의 개체로 보는 것입니다.
왜 이런 규칙이 존재할까요? 보안 때문입니다.
만약 웹사이트가 아무 API나 자유롭게 호출할 수 있다면, 악성 사이트는 다음과 같은 일을 할 수 있습니다:
- 당신의 은행 데이터를 읽을 수 있습니다.
- 개인적인 API에 접근할 수 있습니다.
- 당신을 대신하여 행동할 수 있습니다.
브라우저는 이를 방지하기 위해 동일 출처 정책(Same-Origin Policy)을 사용합니다. 웹사이트 B가 허용하지 않는 한, 웹사이트 A는 웹사이트 B에 접근할 수 없습니다.
CORS는 Cross-Origin Resource Sharing의 약자입니다. 이는 서버가 브라우저에게 다음과 같이 말할 수 있는 방법입니다: "나는 이 특정 Origin으로부터의 요청을 신뢰한다."
백엔드에 다음과 같은 헤더를 추가하여 이 문제를 해결할 수 있습니다:
Access-Control-Allow-Origin: http://localhost:3000
이는 브라우저에게 해당 요청이 안전하다는 것을 알려줍니다.
흔히 혼란을 겪는 부분: 백엔드 로그에는 요청이 도달한 것이 보이는데, 프론트엔드는 실패하는 경우입니다.
이는 다음과 같은 과정 때문에 발생합니다:
- 프론트엔드가 요청을 보냅니다.
- 백엔드가 요청을 성공적으로 수신합니다.
- 백엔드가 응답을 성공적으로 보냅니다.
- 브라우저가 응답을 수신하지만, 보안 규칙에 따라 이를 차단합니다.
이 에러는 브라우저의 보안 기능입니다.
Postman이나 cURL 같은 도구들이 잘 작동하는 이유는 브라우저가 아니기 때문입니다. 이 도구들은 브라우저의 보안 정책을 강제하지 않습니다.
브라우저는 두 앱이 모두 당신의 컴퓨터에 있다는 사실을 무시합니다. 브라우저는 오직 Origin만을 고려합니다.