[React-native] presigned-url 로 s3에 m4a파일 업로드하기

Gyuhan Park·2023년 3월 25일
0

react-native

목록 보기
4/7
post-thumbnail

3가지 방법으로 S3에 접근할 수 있다.
1. 프론트 -> 백 -> S3
2. 프론트 -> S3
3. 프론트 -> 백 -> S3 (presigned-url)

1. 프론트 -> 백 -> S3

일반적인 방법으로 생각할 수 있다.
클라이언트가 사용자의 입력을 받아 서버에 넘겨주면 이를 S3에 저장한다.

2. 프론트 -> S3

클라이언트가 직접 s3에 접근하여 파일을 올린다.
서버를 안거친다는 장점이 있지만 access key를 클라이언트가 가지고 있으므로 보안에 취약하다.
권장하지 않는 방식이라고 한다.

3. presigned-url

이번에 새롭게 적용해본 인증 방식이다.
1번 방식은 음원파일 자체를 서버에 보내야되기 때문에 무겁다는 단점이 있고, 2번 방식은 key값이 브라우저에 노출될 수 있다는 점에서 보안성에 취약하다. 따라서 presigned-url 방식을 채택하였다.

클라이언트는 S3 접근 권한을 얻기 위해 업로드하기 전에 presigned-url을 서버에 요청을 하면 서버가 S3에 인증받은 url을 reponse로 준다.
인증받은 url에 PUT 요청을 보내면 s3에 업로드 할 수 있다. 업로드 후 key값만 서버에 보내서 DB에 key랑 url을 저장하고, 음원을 재생할 때 url을 가져온다.

무수한 삽질

음성파일을 올린다는 게 쉽지 않았다. string도 아니고 number도 아니고 m4a파일을 어떻게 업로드 하는 걸까,,,

파일객체!!! WEB에서는 <input type="file" id="fileUpload" /> 로 파일을 업로드하면 파일객체를 쉽게 얻어낼 수 있다. APP에서는,,,?

const options = {
	method: 'PUT',
	headers: {
		'Content-Type': 'audio/m4a',
	},
	body: bufferFile,
};
await fetch(PRESIGNED_URL, options)

위와 같은 형태로 presigned-url에 PUT 요청을 보내면 업로드가 가능하다.
근데 저 body에 들어가는 부분이 문제다. 어떤 타입의 데이터를 보내야 될 지를 몰랐다.
form, blob, file 등으로 시도했을 때는 업로드되지 않거나 빈파일이 업로드되었다...

몇 일을 삽질한 결과 !!!!!!!

파일관리 모듈의 readFile의 결과값이 Buffer 형식이라는 것을 알게 되었다. 왜 이걸 놓쳤지??? 파일 객체에 사로잡혀 본질을 잊었다.

Buffer는 데이터를 1Byte씩 나누어 저장한다. 보통 이진 데이터를 담아두기 위한 목적으로 사용된다. m4a파일도 결국 이진 데이터일 것이기 때문에 정답이라는 확신을 가졌다.

이미지나 오디오를 ASCII 방식으로 인코딩하여 보낼 경우 시스템마다 다르게 인식하는 값이 존재하여 안전하지 않다고 한다.
64개의 안전한 출력 문자만 사용하는 base64 방식으로 인코딩하여 Buffer 데이터를 전송하였다.

RNFS.readFile(recordingPath, 'base64') : m4a파일을 base64 인코딩 방식으로 읽는다.
Buffer.from : 지정한 값을 담는 버퍼를 생성한다. 지정한 값이 가지는 byte만큼의 메모리가 버퍼에 할당된다.

삽질성공😎

import RNFS from 'react-native-fs';
import { Buffer } from 'buffer';

const fileData = await RNFS.readFile(recordingPath, 'base64');
const bufferFile = Buffer.from(fileData, 'base64');
const options = {
	method: 'PUT',
	headers: {
		'Content-Type': 'audio/m4a',
	},
	body: bufferFile,
};
await fetch(PRESIGNED_URL, options)

S3 권한 설정

퍼블릭 엑세스 차단 해제

버킷정책 추가

{
	"Sid": "PublicPutObject",
	"Effect": "Allow",
	"Principal": "*",
	"Action": "s3:PutObject",
	"Resource": "arn:aws:s3:::tensecond/*"
}

CORS 정책 추가

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "PUT",
            "POST",
            "DELETE"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": []
    }
]

presignedURL 사용하는 이유
Buffer
base64 인코딩방식

profile
단단한 프론트엔드 개발자가 되고 싶은

0개의 댓글