프론트(리액트)에서 파일을 서버 안 거치고 S3로 바로 올리려고 백엔드에서 presigned PUT URL 받아서 fetch로 PUT 하는 구조입니다. 로컬에서 curl로 그 URL에 PUT 하면 잘 올라가는데, 브라우저에서 하면 OPTIONS 요청부터 막히고 콘솔에 CORS 에러가 뜹니다.
Access to fetch at 'https://my-bucket.s3.ap-northeast-2.amazonaws.com/...'
from origin 'https://app.example.com' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.버킷 정책이랑 IAM은 서버가 URL 잘 만들어주는 거 보면 문제 없는 것 같은데, 브라우저에서만 이러니 어디를 봐야 할지 모르겠어요.
댓글 2
버킷 > 권한 > CORS 에 이런 규칙 넣으세요.
[{
"AllowedOrigins": ["https://app.example.com"],
"AllowedMethods": ["PUT"],
"AllowedHeaders": ["*"],
"ExposeHeaders": ["ETag"]
}]
AllowedHeaders에 *를 넣어야 브라우저가 보내는 Content-Type이나 커스텀 헤더가 preflight를 통과해요. 그리고 하나 함정이 있는데, presigned URL 만들 때 Content-Type을 서명에 포함했으면 브라우저 PUT의 Content-Type이 그거랑 정확히 일치해야 합니다. 안 그러면 CORS 통과해도 403 SignatureDoesNotMatch 나요. ExposeHeaders에 ETag 넣은 건 나중에 멀티파트 업로드 하면 ETag를 읽어야 해서 미리 넣어둔 거예요.