-
Presigned url로 s3에 이미지 업로드 하기카테고리 없음 2024. 11. 5. 23:22
배경 및 정의
이미지 혹은 동영상 등의 멀티미디어 파일을 업로드하는 서비스를 구현하기 위해서 요즘에는 presigned url 방식을 많이 활용하고 있다.
presigned url 이란?
AWS에서 제공되는 기능으로 서버와 S3가 통신해서 생성한 미리 서명된 URL을 사용하여 다른 사람이 Amazon S3 버킷에 객체를 업로드하도록 허용할 수 있다. 미리 서명된 URL을 사용하면 상대방에게 AWS 보안 자격 증명이나 권한이 없어도 업로드할 수 있다.
전통적인 S3 이미지 업로드 방식
방법
- 클라이언트에서 서버에게 업로드 할 파일 전달 (multipart/form-data)
- 서버에서 파일 저장 경로를 생성하고 S3에 접근해 파일 저장
- 저장된 S3 경로를 서버에서 클라이언트로 전달
단점
클라이언트에서 서버에게 용량이 큰 파일을 보낸다면 성능 저하의 우려가 생길 수 있다.
S3에 외부에서 직접 접근을 할 수 없다는 점에 있어서는 안전하지만 요청 후 응답까지 걸리는 시간 또는 서버 부하의 우려가 있다.
Presigned Url을 활용하면?
방법
- 클라이언트에서 서버에게 파일 정보 (name, content-type, content-length) 를 전달
- 서버에서 파일 저장 경로 생성 후 S3에 경로에 대한 서명 요청
- S3에서 서버에게 경로에 대한 서명 응답
- 서버에서 클라이언트에게 파일 저장 경로 응답
- 클라이언트에서 S3에 직접 파일 업로드
장점
- 서버의 자원 절약 가능
- 서버와 클라이언트간의 트래픽 절감으로 네트워크 비용 절감
- 제한 시간만 url 이 유효하기 때문에 보안에도 유리
예시 코드
- 클라이언트에서 백엔드에 presigned url 을 만들어 달라는 요청을 보낸다.
- 백엔드 응답
{ "error": { "code": 0, "message": "" }, "payload": { "url": "<https://moida-dev-web-static-assets.s3.ap-northeast-2.amazonaws.com/upload/17302655823428808.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIA2FXAECHJIYD4HRES%2F20241030%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Date=20241030T051942Z&X-Amz-Expires=10800&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEPX%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaDmFwLW5vcnRoZWFzdC0yIkcwRQIgF7MmZ%2BeZLvAySnIAafJXaw%2FZz71cmf9KWyqz7T0JGMICIQCJR1RWsHViuSt9qJHVlfZUQQ2TdK2Rq72FwYwv8DlFMSr%2BAwhuEAAaDDY5OTQ3NTk1NjE3OCIMKWBYlbYleFwYn6i1KtsDOqoQLWuDTVxo6gsWaToGLKnsMHYJcEk%2F8Z%2FjtSjOfa1OzvXVeWEoHcJhjSK2NM%2BrgF8nTHjPXsfL5Sa2ADkvXaIybjuunTsvcSUnDJBRrtwHlpvZxfFHCPFwv0tyYCl6fe6LMBwmXjidiP6QTEYkNZbNKF%2B0Hz6JkMbwtqUKI7t5wIupxbCZNz5cQg0MESHIIGN1wNBRUK6M1qlVmlmfiJk0w%2BE3e8QnoGyQ4ZMwPZxmfLXE1e1FOiiFMRrYQ1pqAq8xhex1sQrmuERLwd3SSSKLIStE0qLbcOB0AU3AzGY9S3%2BZvYzmKuuMjJwdJ1Bof%2FRzoN6mmN59rHj3KsxGPOKieAwJswpnIFEdFObFQttkAu7ufaJRW8YFln%2BwXz4OlW8YcjKHniSPhpWwff52Eg%2BEAKtWCsYB%2Bo3aw2OsYyLuwzgXyWQRePmJ%2BpTq6cN74Ei2uRCYEr4V2VEbamlq%2BlhdEnTU8RHuu5gd5hRst8EwMbeLiiZSfm0U%2FHdRDSaH1Fgt3xLF77ZbRs6HdQl9GiPNELfVzy%2FYo2hcUp7ywaosF8A0SLC9VMwo051Q6EgeXeLpGQDASj0VTnecOaYmlRAzHoZQDGGLwtgqZ4VKpjK5cX65sxEe%2Bcni6DCMg4e5BjqlAQvRX7%2FcGaj8vR0Kc8GZkY9wNsFVy%2BhKsLp5Aj2H6d6H7VRfnnFdWhe%2BYPClsM7RW7bAL2quoNcs3ey62Fipl3bP%2FMIGEkBJyaOqRv0e4M8HxLkBUJ0aqiENBEuhxd5XLokAomqJ8SPPIOSeu4680%2BfsY57aynyxvgUGZO7Jv6zaS%2BnBim83li1DHO59PajOJpi%2B%2BAvindaju0LX3I%2BnfltzgkTU%2Fg%3D%3D&X-Amz-Signature=47889758718c88e7ed287af75bb436f00488939fcc40150e3533771b111b6701&X-Amz-SignedHeaders=host>", "cfUrl": "<https://static.moxda.store/upload/17302655823428808.png>" } } url : 파일 업로드할 때 사용할 presigned url cfUrl : 파일 업로드 성공하면 사용 할 cf 의 서비스용 url
- 백엔드에서 받아 온 presigned url 을 활용해서 S3 에 이미지를 바로 업로드 하는 코드
export const uploadImageToS3 = async (presignedUrl: string, file: File) => { const response = await fetch( new Request(presignedUrl as string, { method: 'PUT', body: file, headers: new Headers({ 'Content-Type': 'image/*', }), }), ) if (response.status !== 200) { console.error('Failed to upload image to S3') return } return response }
에러 핸들링
위의 코드를 통해서 S3에 업로드를 하려는데 cors 에러가 나요!
-> AWS 콘솔에 접속해 해당 S3의 버킷에 들어간다.
권한 탭에서 다음과 같이 작성한다.
- AllowedMethods: Http 메소드들 중 다음을 허용한다.
- AllowedOrigins: 다음 오리진을 허용한다. (클라이언트 주소)
[ { "AllowedHeaders": [ "*" ], "AllowedMethods": [ "PUT", "POST", "DELETE" ], "AllowedOrigins": [ "http://localhost:3000" ], "ExposeHeaders": [] } ]
추가 지식 - Signed url 과 presigned url은 무슨 차이?
Presigned URL
- 사용자가 S3 같은 저장소에서 파일을 업로드하거나 다운로드할 수 있도록 권한을 위임하는 URL
- 일반적으로 클라이언트가 직접 파일에 접근할 수 있도록 허용하는 방식
- 서버에서 URL을 생성할 때 만료 시간을 지정할 수 있으며, 만료 후에는 URL이 무효화
- 서버 측에서 클라이언트에게 임시 접근 권한을 부여하는 형태로, 클라이언트가 직접 파일을 업로드하거나 다운로드할 때 유용
Signed URL
• 인터넷을 통해 콘텐츠를 배포하는 많은 기업에서는 유료 사용자 등 일부 사용자용으로 제작된 각종 문서∙비즈니스 데이터∙미디어 스트림 또는 콘텐츠에 대한 액세스를 제한하고자 함
- Signed URL은 서버가 리소스를 제공하는 보안 URL이며, 서버와 서버 간의 통신 또는 보안 접근이 필요한 경우에 주로 사용
- 미리 서명된 파라미터를 포함한 URL로 특정 리소스에 대한 접근 권한을 증명
- 일반적으로 클라이언트보다는 서버 간의 보안 통신이 필요한 경우, 예를 들어 백엔드 서버와 리소스를 주고받을 때 자주 사용
주요 차이점 요약
- Presigned URL은 주로 클라이언트가 특정 시간 동안 리소스에 직접 접근할 수 있도록 하는 데 쓰이며, 파일 업로드 및 다운로드에 적합
- Signed URL은 보안이 필요한 서버 간 접근에 주로 사용되며, 클라이언트보다는 백엔드 서버 간 통신에 적합
참고 블로그