통상적으로 컨텐츠의 업로드는 인증로직과 관계되어 서버에서 처리되는 경우가 많다.
한편 동영상을 업로드하는 경우, 여러 확장자 파일과 수GB파일 단위의 영상파일을 업로드하게 되는데 이때 서버를 경유해서 처리시 아래와 같은 문제가 있다.
- 비효율적인 리소스 활용 (영상을 서버에 넘겨주는 처리와 서버에서 영상을 스토리지에 업로드하는 작업)
- 서버의 스토리지 용량관리
- 각종 대응(타임아웃, 동기화/비동기화 고려)
이러한 문제를 해결하기 위해 컨텐츠(영상)을 서버에 보내서 업로드하지 않고 클라이언트에서 직접 스토리지(이 포스트에서 소개하는 스토리지는 S3)에 업로드 하는 방법이 등장했다.
S3에서는 pre-signed URL
을 이용해 구현이 가능하다.
S3의 Presigned URL에 대해서는 다른 포스트에서 자세히 설명할 예정이다. 이 포스트에서는 가볍게 사용방법만 언급한다.
대략적인 구현방법
1.
서버에서 어떤 디렉토리에 컨텐츠를 업로드 할것이라는 정보를 관리한다. 해당 정보를 A라는 변수에 담았다고 해보자.
A = "#{dir}/#{file_name}"
2.
A라는 변수에 있는 path를 이용해presigned_url(:put)
을 발행해준다.
ruby코드로는 아래와 같다.
bucket = Aws::S3::Resource.new.bucket(ENV['BUCKET_NAME'])
obj = bucket.object("#{dir}/#{file_name}")
obj.presigned_url(:put)
3.
presigned_url(:put)
을 실행해주면 크게 두가지 액션이 실행된다.
실제 해당 S3상에 0byte의 파일이 생성됨
bucket명 xxx에 images/xx.mp4
라는 path였다면 해당 path의 S3에 0byte의 파일이 만들어진다.
presigned_url 발행
아래와 같은 presigned url이 발행된다. 해당 URL은 디폴트 유효기간이 15분이고(최대 7일까지 가능) 그 시간이 지나면 사용이 불가능하다.
https://xxx.s3.amazonaws.com/images/xx.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAVZH4SBSY4EO3QIWS%2F20210428%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20210428T112140Z&X-Amz-Expires=900&X-Amz-SignedHeaders=host&X-Amz-Signature=20e494910e73bde0404aa4ccaf6b10a8690a3ceff16489e2e72a82b879a4d39f
4.
서버는 3에서 생성한 presigned_url을 클라이언트에 넘겨준다.
5.
클라이언트는 4에서 전달받은 presigned_url을 이용해 직접 파일업로드가 가능하다.
해당 url에 REST로 put을 해주면 업로드가 가능하다.
flutter에서 image파일 업로드시 사용하는 코드를 첨부해둔다.
Future<void> uploadImage(String url, File image) {
final Dio dio = Dio()..interceptors.add(LogInterceptor(responseBody: true));
dio.options = BaseOptions(contentType: 'image/jpeg');
return dio.putUri<void>(Uri.parse(url),
data: image.openRead(),
options: Options(headers: <String, dynamic>{
HttpHeaders.contentTypeHeader: ContentType('image', 'jpeg'),
HttpHeaders.contentLengthHeader: image.lengthSync(),
}));
}
클라이언트에서 작업할때 알고 있으면 좋을 포인트로는 아래와 같은것이 있다.
- presigned_url을 이용하면 업로드할 s3 bucket policy를 무시한다.(s3:PutObject Deny라고 해도 가능?)
- presigned_url을 디폴트 유효기간인 15분내에 업로드가 가능(시간이 지나면 불가능하므로 15분내에 처리해야함)
- 특정 object의 acl권한도 안보는듯?(FULL_CONTROL망 있고 public-write 아니어도 가능했음, FULL_CONTROL이 필수인지는 미검증)
메모
예전 기사를 보면 S3 put처리는 용량제한이 있는듯??
컨텐츠의 용량에 따라 lambda등을 경유해서 처리할 필요가 있을지도