최근 프로젝트에서 애니메이션 라이브러리인 Rive를 사용하고 있는데, 기존에는 AWS S3 버킷에서 직접 .riv 파일을 다운로드 받는 방식으로 구현했습니다. 그런데, CDN의 장점을 활용해서 성능도 개선하고, 비용도 절감할 수 있다는 얘기를 듣고, CloudFront를 도입하여 CDN 링크로 변경하는 작업을 진행하게 되었죠.
처음엔 "그냥 URL만 바꾸면 되는 거 아냐?"라고 안일하게 생각했었는데... 이게 웬걸? CORS(Cross-Origin Resource Sharing)라는 복병을 만나게 될 줄은 꿈에도 몰랐습니다. 오늘은 제가 S3에서 직접 받던 .riv 파일을 CloudFront CDN 링크로 변경하면서 겪었던 CORS 에러와 그 해결 과정을 회고하며 공유해볼까 합니다.
🤦♂️ 시작은 순조로웠다... (feat. S3 버킷 URL)
처음에는 모든 것이 순조로웠습니다. S3 버킷에 .riv 파일을 업로드하고, https://[버킷 이름].s3.[리전].amazonaws.com/[경로] 와 같은 형식의 URL을 통해 파일을 잘 가져올 수 있었습니다. axios 대신 fetch를 사용하는 방식으로 변경했고, arraybuffer 형태로 데이터를 잘 받아와 Rive 컴포넌트에 적용했습니다.
// 기존에 S3 버킷에서 직접 파일을 가져오던 코드 (정상 작동)
const fetchRive = async (riveUrl: string) => {
const response = await fetch(riveUrl);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const arrayBuffer = await response.arrayBuffer();
return arrayBuffer;
};
🤔 CDN 도입, 그리고 CORS 너 정체가 뭐냐...?
프로젝트 규모가 커지면서, S3 버킷에서 직접 파일을 가져오는 방식은 글로벌서비스를 개발하는 입장에서 여러모로 비효율적이라는 생각이 들었습니다. 그래서 AWS CloudFront를 도입하여 CDN을 구축하고, .riv 파일을 CDN 링크를 통해 가져오도록 변경했습니다.
cdn이란?
콘텐츠 전송 네트워크(CDN)는 사용자에게 웹 콘텐츠를 더 빠르고 효율적으로 제공하는 데 사용되는 지리적으로 분산된 서버 네트워크입니다.
일반적으로 웹사이트의 이미지를 보려면 사용자가 웹사이트 서버에 요청을 보냅니다. 서버가 멀리 떨어져 있는 경우 이미지를 로드하는 데 시간이 걸릴 수 있습니다. CDN은 서버의 부하를 줄이고 웹사이트 성능을 개선하기 위해 사용자와 더 가까운 서버에 이미지와 같은 웹사이트의 정적 자산의 사본을 저장합니다.
CDN을 사용하는 이유
로딩 시간 단축: CDN은 사용자와 더 가까운 서버에서 콘텐츠를 전송하여 웹페이지 로딩 시간을 단축합니다.
대역폭 비용 절감: CDN은 원본 서버의 대역폭 사용량을 줄여 대역폭 비용을 절감하는 데 도움이 됩니다.
안정성 향상: CDN은 여러 서버에 콘텐츠를 저장하여 원본 서버에 문제가 발생하더라도 웹사이트를 계속 사용할 수 있도록 합니다.
"이제 성능도, 비용도 모두 잡았다!"라고 생각하며 코드를 수정하고 실행했는데... 웬걸? 브라우저 콘솔에 빨간색 CORS 에러 메시지가 저를 반겨주더군요.
CORS는 브라우저의 보안 정책 중 하나로, 다른 출처(Origin) 로의 리소스 요청을 제한하는 것이라고 하더군요. request를 보내고 있는 CDN 도메인이 제가 개발 중인 웹 앱의 도메인(localhost 또는 개발 도메인)과 다르기 때문에 발생한 문제였습니다.
🥊 삽질의 연속, CORS와 맞짱 뜨기
처음에는 Next.js의 next.config.js 파일에서 rewrites 설정을 만져보기도 하고, headers 설정을 추가해보기도 했지만, 모두 소용없었습니다. rewrites는 클라이언트 사이드 요청에만 영향을 미치고, headers 설정은 서버 간 통신에는 적용되지 않는다는 것을 뒤늦게 깨달았죠.
결국, 이 문제는 NextJs의 SSR에 기반한 서버간 통신이기 때문에 CloudFront와 S3 설정에서 해결해야 한다는 것을 알게 되었습니다.
💡 삽질 끝에 찾아낸 해결책: CloudFront와 S3, CORS 설정 콤보!
여러 번의 삽질 끝에, 다음과 같은 방법으로 CORS 에러를 해결할 수 있었습니다.
1. S3 버킷 CORS 설정:
S3 버킷의 권한 설정에서 CORS 설정을 추가해야 했습니다. 중요한 것은 AllowedOrigins에 제 웹 앱의 도메인을 모두 허용해야 한다는 것이었습니다.
2. CloudFront "동작(Behaviors)" 설정:
CloudFront 배포의 "동작(Behaviors)" 탭에서 Origin 헤더를 S3 버킷으로 전달하도록 설정하는 것이 핵심이었습니다. (중요!)
- 캐시 정책(Cache policy) 및 원본 요청 정책(Origin request policy):
- Managed-CORS-S3Origin 정책을 선택하거나,
- Legacy cache settings를 선택하고, Headers에서 Origin을 추가하거나,
- 사용자 지정 정책을 사용하는 경우, Origin 헤더를 헤더 포함(Include headers) 목록에 추가해야 했습니다.
3. CloudFront 캐시 무효화:
CloudFront 설정을 변경한 후에는, 반드시 캐시를 무효화해야 변경 사항이 적용됩니다.
🎉 CORS 에러, 드디어 안녕!
위와 같이 설정하고 나니, 드디어 CORS 에러가 사라지고 CDN 링크를 통해 .riv 파일을 정상적으로 다운로드 받을 수 있게 되었습니다!
📚 교훈 및 느낀 점
- CORS는 브라우저 보안 정책이라는 것, 그리고 서버 측 설정이 가장 중요하다는 것을 뼈저리게 느꼈습니다.
- next.config.js 설정은 클라이언트 사이드 요청에만 영향을 미친다는 것을 알게 되었습니다.
- AWS CloudFront와 S3를 사용할 때는, 두 서비스의 설정을 모두 꼼꼼하게 확인해야 한다는 것을 배웠습니다.
- "그냥 URL만 바꾸면 되겠지"라는 안일한 생각은 금물! 꼼꼼한 사전 조사와 테스트가 중요하다는 것을 다시 한번 깨달았습니다.
- "헤멘만큼 내땅!" 이번 경험을 통해 CDN 서비스의 CORS는 잡을 수 있게 되었습니다!
이 글이 저와 같이 파일을 CDN으로 옮기면서 CORS 에러로 고생하시는 분들께 조금이나마 도움이 되었으면 좋겠습니다. 삽질은 괴롭지만, 그만큼 값진 교훈을 얻을 수 있는 기회이기도 하니까요! 💪
'FE 개발' 카테고리의 다른 글
[FE] GraphQL & Axios 사용법 (0) | 2024.03.26 |
---|---|
[FE 개발] 가상 돔과 실제 돔 (0) | 2024.01.18 |
[FE 개발] 프레임워크와 라이브러리 (0) | 2024.01.17 |
[FE 개발] 동기와 비동기 (0) | 2024.01.17 |
[Git] commit 이력 대거 수정 (Git filter repo) (3) | 2023.12.06 |