nueijeel

[Android] 안드로이드에서 PreSigned URL을 이용해 AWS S3에 이미지 업로드 하기 (1) 본문

Android/에러 및 문제 해결

[Android] 안드로이드에서 PreSigned URL을 이용해 AWS S3에 이미지 업로드 하기 (1)

nueijeel 2024. 4. 3. 21:27

 

세모반 프로젝트 배포 후 백엔드 개발자분께서 이미지 처리 로직 변경을 제안해주셔서 새로 구현한 방식에 대해 포스팅하려고 한다.

 

 

기존 이미지 처리 로직

기존에는

클라이언트에서 Post api를 호출해 서버로 데이터를 전송하면 서버는 수신한 데이터를 처리해 aws에 직접 이미지를 업로드하는 로직이었다.

(데이터 전송 형태는 multipart/form-data 형식으로 전달)

 

 

하지만 이 방식은 클라이언트가 서버에 api 통신을 요청하는 횟수가 많아질수록 서버 부하가 발생한다는 단점이 있다.

 

 

아직까지 세모반은 사용자가 많지 않은 상태라 위 방식으로 처리를 해도 큰 문제가 없지만,

 

 

애초에 앱 개발을 시작할 때 지속적으로 서비스하는 앱을 만드는 게 목적이었기 때문에

추후에 사용자가 많아져 서버 통신량도 증가할 경우를 미리 대비해 새로운 이미지 처리 로직으로 변경하게 되었다.

 

 

새로운 이미지 처리 로직

 

 

새로운 방식에서는

클라이언트가 서버에 PreSigned URL을 요청해 반환받고, 해당 주소를 통해 클라우드에 직접 이미지를 업로드 하는 과정으로 이미지를 처리하게 된다.

 

 

이 방식으로 처리할 경우

 

1. 클라이언트가 서버를 통하지 않고 AWS에 직접 이미지를 업로드하기 때문에 보안과 속도 측면에서 이점

2. 서버가 PreSigned URL을 생성하고 전달하는 과정만 담당하기 때문에 부하를 줄일 수 있음

3. 서버로 이미지 전송 시 10MB로 용량이 제한되지만 클라이언트가 직접 처리 시 단일 요청에 대해 5GB의 용량이 지원됨

 

위와 같은 측면에서 이점을 갖는다.

 

 

PreSigned URL이란?

✔️ PreSigned URL은 S3 소유자가 자격 증명을 사용하여 특정 권한에 대해 서명을 완료한 URL이다.

 

서버에서 특정 객체에 대한 접근을 허용하기 위해 클라이언트에 PreSigned URL을 제공하면 클라이언트는 해당 URL을 사용해 파일 업로드나 다운로드 같은 작업을 수행할 수 있다.

 

또, 서버에서 PreSigned URL을 생성할 때 만료 시간을 지정할 수 있기 때문에 안전한 사용이 가능하다.

 

 

 

 


 

 

 

 

구현하기

기존에 POST api를 호출하는 부분에 변경된 로직을 적용해보려고 한다.

 

 

1) PreSigned URL 요청하기

Interface

우선 서버에 PreSigned URL을 요청하는 interface 메서드를 먼저 작성해준다.

 

 

Repository + Impl

Repository에 getPresignedUrl 함수를 정의하고

 

구현체에서 Repository를 상속받아 api를 호출하는 코드를 작성한다.

 

 

ViewModel

ViewModel에서 Repository를 주입받아 함수를 호출하고, 받아온 response를 LiveData에 저장했다.

 

 

View

View에서 createMultipartFromUri 함수를 이용해 uri를 MultipartBody.Part 형식으로 변환하고, FilePath를 지정해 getPreSignedUrl 함수를 호출한다.

 

여기서 두번째 인자로 전달되는 filePath 값은 aws s3 버킷 내에 이미지가 저장될 상세 경로가 담긴 문자열이다.

 

예를 들어서 Animal이라는 S3 객체 하위에 animal-image라는 폴더가 있고, 그 하위에 dog, cat 등의 폴더가 존재한다고 할 때

cat 폴더 하위에 munchkin이라는 이름의 파일을 저장하기 위해서는

"animal-image/cat/munchkin" 과 같은 문자열을 넣어주면 된다.

 

그러면 해당 경로에 이미지를 업로드할 수 있는 권한이 서명된 url을 얻을 수 있다.

 

 

 

2) PreSigned URL로 이미지 업로드하기

Interface

PreSignedURL에 이미지를 PUT하는 메서드를 작성해준다. 

 

이미지는 Multipart 형식으로 전달할것이기 때문에 @Multipart 어노테이션을 명시했고, @Part 어노테이션으로 멀티파트 요소를 정의했다.

 

 

이미지를 어떤 형식으로 전달해야 하는지 몰라서 구글링을 엄청 했는데도 내가 구현하려는 방법이 아니라 AWS SDK를 사용하는 방법만 많이 나왔다...

 

 

결국 백엔드 분께 질문을 드렸더니

이렇게 답변을 주셔서

 

일단 그나마 내 방법과 가장 근접하게 구현됐다고 생각되는 스택오버플로우의 솔루션을 참고해 multipart 형식으로 이미지를 전달하게 되었다. 

 

 

Repository + Impl

Repository에 uploadImageToS3 함수를 정의하고

구현체에서 Repository를 상속받아 api를 호출하는 코드를 작성한다.

 

 

ViewModel

ViewModel에서 Repository를 주입받아 함수를 호출하고, 받아온 response를 LiveData에 저장했다.

 

 

View

앞서 호출한 getPreSignedUrl 함수를 통해 성공적으로 통신이 이루어지면

View에 등록된 Observe를 통해 PreSigned URL을 얻을 수 있다.

 

 

얻은 url로 이미지를 업로드하면

 

 로그를 통해 이미지 업로드에 성공했음을 알 수 있다 !

 

 

 

 

 

 

 

 

 

728x90