티스토리 뷰
문제 상황
FE에서는 그동안 CloudFront URL로 만들어진 이미지 URL을 BE로부터 전달 받아서 img 태그에 넣어주기만 했었다.
그런데 이번 개선으로 이미지를 다운로드를 받아서 사용할 일이 생겼다.
그런데 웬걸 CORS 에러가 발생하기 시작했다.
FE에서는 fetch를 이용해 이미지를 blob형태로 받으려 했고, 이 과정에서 CORS가 발생했다고 한다.
이 문제의 원인을 찾아가는 과정이다.
문제 분석
1. CloudFront에서 특정 HTTP Method를 막아놨나?
- 이전에 CloudFront로 POST 요청이 필요한 경우가 있었는데, 이 Method가 막혀 있을 때 비슷한 에러가 났었다.
그러나 fetch는 GET 방식이고, CloudFront에서 GET 방식은 무조건 열려있다.
2. S3의 CORS 설정이 문제인가?
AWS 콘솔에서 S3 버킷 > 권한 탭에서 아래로 내려보면 > CORS(Cross-origin 리소스 공유)가 있다.
S3의 CORS 헤더 설정은 JSON으로 작성하면 되는데, 작성법은 AWS에서 친절하게 작성해두었다.
https://docs.aws.amazon.com/ko_kr/AmazonS3/latest/userguide/testing-cors.html
현재 문제가 있는 S3 버킷의 CORS 설정은 정상적으로 되어있었다.
FE에서 사용하는 도메인들 모두 AllowedOrigins로 적절하게 설정되어 있었고, AllowedMethods도 필요한 Method들이 모두 허용되어 있었다.
3. CloudFront 캐시 원본 설정의 문제인가?
AWS CloudFront의 헤더 정책에 자세히 알지 못했던 내가 생각하기엔 아무런 문제가 없어보였다.
그런데 CloudFront에서 캐시 무효화를 하면 일시적으로 CORS가 나지 않았다.
그리고 S3로 직접 요청을 하면 별 문제 없이 이미지를 다운로드 할 수 있었다.
여기서 힌트를 얻었다.
결론은 CloudFront 쪽에서 응답 헤더 관리가 잘못되고 있었다.
그렇다면 CloudFront에서 응답 헤더를 어떻게 핸들링할 수 있을까?
해결법
클라이언트가 요청한 데이터는 다음과 같이 움직인다.
클라이언트 → CloudFront → S3 → CloudFront → 클라이언트
여기서 문제가 발생한 부분은 CloudFront → 클라이언트 이 부분이다.
첫 요청부터 문제가 생겼다면 클라이언트 → CloudFront → S3 이 부분도 문제가 있었겠지만,
캐싱되기 전에는 요청이 잘 되고 있으며 S3 직접 접근도 문제가 없었기 때문이다.
문제를 해결하기 위해선 CloudFront에서 응답 헤더 정보를 수정해야한다.
원본 요청 정책은 클라이언트가 요청한 헤더 중 어느 것들을 S3로 보내주겠냐는 것을 의미한다.
CORS-S3Origin은 S3로 CORS 관련 헤더를 그대로 요청하겠다는 뜻이다.
(이 외에도 여러가지 매니지드 설정들이 있다. 커스텀도 가능하니 이 링크를 참고해서 설정해보자)
만약 CDN 없이 S3만을 사용했다면, S3에서는 요청한 헤더에 대한 정보를 모두 응답 헤더에 포함해 내려줬을 것이다.
그렇다면 현재 상황은 S3에서 내려준 응답을 CloudFront에서 모두 내려주지 않았다는 게 된다.
결론은 응답 헤더 정책에 문제가 있다는 것이다.
위에서 강조한 SimpleCORS도 AWS에서 제공하는 매니지드 설정인데, 이 설정을 열어보면 다음과 같다.
만약 fetch 중에 Pre-flight Request가 발생했다면, 서버가 어떤 매서드를 허용하는지 알 수 없어 CORS가 발생했을 것이다.
그래서 Access-Control-Allow-Methods 와 같이 어떤 서버가 어떤 매서드를 허용하는지 알려주는 응답 헤더가 없나
알아보니 CORS-With-Preflight 설정을 발견하고 이를 선택했다.
이렇게 설정하고 나니 FE에서 정상적으로 이미지 데이터를 fetch 받을 수 있게 되었다.
왜 Pre-Flight Request가 발생했는가?
사실 이게 가장 중요한 문제고, 아직 이유를 찾지 못했다.
단순 GET 방식 같아보이는 fetch 요청을 보냈을 때, 왜 Pre-Flight Request가 발생했을까? MDN 문서를 확인해보자.
https://developer.mozilla.org/ko/docs/Glossary/Preflight_request
MDN 문서에서는 단순 GET 방식에서는 Pre-Flight Request가 발생하지 않는다. 라고 하는데,
이미지를 다운로드 요청을 하는 fetch의 경우에는 단순한 GET 방식의 요청이 아니었나보다.
위 내용은 의심스러운 것 중 하나다.
FE localhost에서 cors가 발생한거라 dev로 올렸으면, 도메인이 일치하게 되는데 그럴 경우 사전 요청이 안나가서 잘 동작했을까?
그리고 FE에서는 fetch 할 때 따로 CORS 관련 요청 헤더를 설정하지 않았다고 했다.
그렇다면, CloudFront의 요청/응답 헤더 설정과 S3에서 CORS를 열어놓은 과정에서 브라우저가 추가 요청을 해야하는 상황이 발생하지 않았을까?
이게 가장 합리적인 의심인데 결국 아직 해답을 찾지 못 했다.
내가 이 문제를 제대로 파악해서 수정하기 전에는 FE에서 서버사이드로 데이터를 주고받도록 처리했다.
서버 투 서버로 데이터를 주고받게 됐으니 자연스럽게 CORS 문제는 해결됐지만,
아무리 생각해봐도 올바른 해결책은 아니어서 한번 더 알아보고 문제를 수정할 수 있었다.
정확히 파악하기 전에는 다음과 같이 Cache-Control: no-store 같은 옵션도 줘봤지만 될리가 없었다.
https://yozm.wishket.com/magazine/detail/1782/
마치며
AWS의 CloudFront 초기 설정을 내가 담당했었으면 이 문제는 쉽게 해결됐을지도 모르겠다.
S3 연동 부분의 사소한 블랙박스가 이런 문제를 발생시킬지는 상상도 하지 못 했다.
분명 이 설정을 보긴 봤는데, 별 생각없이 넘겼었다.
한발짝 더 들어가봤으면 시간을 아낄 수 있었지 싶다 ㅠ
백엔드 피쳐개발이 빠르게 돌고 있을 때 이런 문제가 들어오게되면 세세하게 봐주지 못해서 아쉬운 부분이다.
'개발 > 개발팁' 카테고리의 다른 글
월드 ID(world coin)로 인증하기 with. SpringBoot (1) | 2024.03.30 |
---|---|
Windows 10에서 Phython requirements.txt 자동 생성하기(파이썬 패키지 의존성 자동 생성) (0) | 2024.02.19 |
Windows 10에서 WSL1을 WSL2로 업데이트하기 (1) | 2024.02.10 |
SpringBoot에서 Google Indexing API 사용하기 1 (1) | 2024.02.02 |
Windows에서 AWS EC2 접속 시 UNPROTECTED PRIVATE KEY FILE 에러 해결하기 (0) | 2024.01.20 |
- Total
- Today
- Yesterday
- 람다
- lambda
- Elastic cloud
- Kotlin
- terraform
- serverless
- JWT
- OpenFeign
- openAI API
- AWS
- 티스토리챌린지
- OpenAI
- MySQL
- java
- 오블완
- cache
- docker
- S3
- AOP
- GIT
- 후쿠오카
- Log
- AWS EC2
- springboot
- EKS
- CloudFront
- ChatGPT
- 스프링부트
- elasticsearch
- Spring
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |