본문 바로가기
React

AWS S3 presignedURL을 이용한 이미지 파일 업로드

by 검소한달걀 2024. 8. 30.

 

Presigned URL

Pre-signed URL은 AWS S3에 이미지를 업로드할 때, 해당 S3의 접근 권한 인증을 마친 후 발급받는 URL이다.

 

사용 이유

1. 프론트에서 서버를 거치지 않고 S3에 직접 파일을 업로드하기 때문에

   서버가 업로드 요청을 처리하는 데 필요한 리소스를 절약할 수 있다.

2. 백엔드에서 권한 설정을 한 url이기 때문에 보안이 강화된다.

 

전체 아키텍처

1. 클라이언트에서 서버에 presigned URL 요청 (POST)

2. 서버는 이 요청을 S3에 전달

3. S3는 새로운 presigned URL을 서버에 반환

4. 서버는 다시 이 presigned URL을 클라이언트에 전달

5. 클라이언트는 사용자가 선택한 파일을 S3에 직접 업로드 (PUT)

6. 클라이언트는 업로드가 완료되었음을 알리는 요청을 서버에 전달

 

 

POST 요청

 

export const postPresignedURL = async (fileName: string) => {
    const response = await fetch(`${API_BASE_URL}/users/presigned-url`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            fileName
        })
    });
    if (!response.ok) {
        throw new Error('AWS S3 에서 presigned URL 응답 실패');
    }
    return response.json();
};

 

 

서버에 요청을 보내면 아래와 같은 presigned URL을 반환받는다.

 

 

PUT 요청

 

export const uploadFileToS3 = async (presignedURL: string, file: File) => {
    const response = await fetch(presignedURL, {
        method: 'PUT',
        body: file
    });

    if (!response.ok) {
        throw new Error('AWS S3로 파일 업로드 실패');
    }
    // PresignedURL에서 ?앞 부분이 파일 url
    return presignedURL.split('?')[0];
};

 

전달받은 presigned URL을 이용해 클라이언트에서 이미지 파일을 S3에 바로 업로드한다.

이때 이미지를 특정한 위치(정해진 presigned URL)에 저장하기 때문에 POST가 아닌 PUT 메서드를 사용한다.

 

 

정리 - 구현 코드

 

    const UploadImageToS3 = async (file: File) => {
        try {
            const { presignedURL } = await postPresignedURL(file.name);
            const fileUrl = await uploadFileToS3(presignedURL, file);
            return fileUrl;
        } catch (error) {
            console.error('파일 업로드 에러:', error);
            throw error;
        }
    };


    const handleImageUpload = async (
        e: React.ChangeEvent<HTMLInputElement>
    ) => {
        if (!e.target.files) return;
        const file = e.target.files[0];
        if (file) {
            try {
                const fileUrl = await UploadImageToS3(file);
                setProfileImg(fileUrl);
            } catch (error) {
                console.error('이미지 업로드 중 오류 발생:', error);
            }
        }
    };

 

1. postPresignedURL에 file.name을 전달해 S3에서 사용할 Presigned URL을 생성한다.

   이 file.name은 S3에서 저장할 파일 이름으로 사용된다.

2. uploadFileToS3에  Presigned URL과 file을 넘겨 file url을 전달받는다.

    이 file url은 Presigned URL에서 ?앞 부분 -> presignedURL.split('?')[0]으로

    클라이언트에서 이미지를 미리 보기 위해 사용되며, 실제로 S3에 저장된 이미지의 경로를 나타낸다.

 

 

 

 

참고
https://medium.com/developing-koan/uploading-images-to-s3-from-a-react-single-page-application-45a4d24af09f

 

'React' 카테고리의 다른 글

React-Hook-Form 알아보기 - useForm / useFormContext  (1) 2024.06.28