[AWS S3] Lambda로 Presigned url 발급해 클라이언트가 직접 버킷에 객체 업로드하게 하기

원래 사용했던 업로드 방법

원래는 서버에 클라이언트가 Formdata 형태로 이미지 파일을 전달하고, 서버에서는 로컬에 해당 이미지를 저장해 File로 변환 후 s3 client를 이용해 버킷에 객체(이미지)를 업로드 하는 방식을 썼었다.

fun convertMultipartToFile(multipartFile: MultipartFile): File {
    val convertedFile = File(System.getProperty("user.dir") + "/" + multipartFile.originalFilename)
    if (convertedFile.createNewFile()) {
        val fos = FileOutputStream(convertedFile)
        fos.write(multipartFile.bytes)
        return convertedFile
    }
    throw IllegalStateException("파일 변환 실패")
}

여기서 반환된 File을 s3Client의 putObject를 이용해 업로드 했었다.

여러 토이프로젝트에서 사용하는 방법이고, 나도 그동안 api를 개발하면서 항상 이 방식을 썼었다.

이전 글에서 나타난 문제는 바로
iOS 기기에서는 이미지 크기 리사이징이 자동으로 되지 않아서, 파일의 크기가 너무커져 nginx단에서 요청을 거부하는 것이었다.
앱 서버를 거쳐야하는 이유는 하나도 없었다. 근본적인 문제를 알게 된 이상 계속 이 방법을 쓰면 안된다고 생각했다.

리사이징? 아니, 업로드 주체부터 바꾸자

  • 사이즈가 너무 커서 그런 것도 당연히 이유 중 하나였다.
  • 그런데 근본적인 문제를 해결하기 위해서는 이유없이 앱서버를 거치는 과정부터 바꿔야한다고 생각했다.
  • 리사이징 또한 클라이언트에서 바로 이뤄지는 것보다는 버킷에 올라간 후 다른 주체가 진행하는 것이 대부분이었다. 버킷에 원본을 올리는 과정 자체의 문제를 해결해야한다.

리자이징 예제(다른 블로그)

여기서두 s3에 원본 업로드 하고, 그 이벤트를 트리거로 삼는 lambda에서 리사이징을 하도록 했다.


많은 해결방법들 중, 나는 presigned url을 사용하기로 했다.

Presigned url 도입 계기

  • 배경은 다음과 같다
  • nginx와 spring boot의 request size를 계속해서 늘이며 multipart form data size limit을 해결하며 너무 찝찝했고
  • 이 limit이 있는 이유를 찾아봤지만 명확한 이유를 없었다(너무 당연한 거라 그런 거같았다 .. ㅜ 하지만 난 모르는걸,)

그래서 회사 분들에게 물어봤더니 멘토분에게 5초만에 답이 달렸다 .. 최고

바로 도입!
본 포스팅에서는 presigned url이 뭔지는 얘기 안함
AWS 문서 를 보면 이렇게 써있다.

내가 발급 받은 방법

  • 클라이언트에서 credential을 가지고 있으면 털릴 위험이 높아지므로 presigned url을 s3에게서 발급받는 애는 다른 애가 되어야한다고 생각했다.
  • 그래서 lambda 함수를 썼다. 그래서 credential은 람다만 가지고 있다.

  • 실제로는 람다가 발급받고, 웹은 그걸 사용해서 사진 업로드 하는 것임.

결과 🙏🏻

앱 서버는 더이상 이미지 업로드에 관여하지 않는다

클라이언트에서 람다에게 사진 업로드 요청을 보낼 presigned url을 얻어서 직접 사진을 업로드 한다.

앱 서버는 이미 업로드된 사진의 url을 직접 받아 데이터베이스에 저장하기만 하면 된다.

하휴, 진작 이렇게 할걸ㄹ

좋은 웹페이지 즐겨찾기