지금까지 서버에 이미지 저장하는건 그냥 post로 냅다 이미지 url 보내고 불러다쓰고 하는 방식만 써왔는데 사실 이 이미지를 처리할때 이미지를 통쨰로 서버와 주고받는건 굉장히 안좋다. api 통신을 할때 string 데이터들은 KB 단위도 안 되는 크기지만 이미지는 MB 단위라 multipart나 body에 담아서 전송하는 행위는 다른 api 통신에 비해 리소스가 몇 배 이상 소모된다.
그래서 이미지 데이터 통채로 백엔드에 전달하여 DB에 전달하는것이 아닌 이미지에 접근 가능한 url만 전달해서 저장할 수 있도록 해야한다.
이렇게하면 리소스를 매우 크게 줄일 수 있다.
그럼 위와 같은 방식을 어떻게 해야할까?
프론트가 이미지를 바로 스토리지에 업로드하고 그곳에 접근할 수 있는 url을 뽑아와서 서버에 전달해야한다.
이때 나는 이미지 저장소로 aws S3를 사용했다.
유저가 이미지를 추가하면 s3스토리지에 이미지들을 업로드하게 하고, 이 저장소에 업로드된 이미지의 주소를 백엔드에게 imageUrl로 넘겨주었다. 근데 이때 s3는 데이터파일 조회 및 다운로드를 제외하고 이외의 모든 권한은 서비스의 저장소 파일들을 아무나 막 삭제하거나 수정하면 안되기 때문에 막아둬야한다. 그래서 단순히 업로드하는 것이 아닌 s3에 업로드 가능한 권한을 부여받은 뒤 업로드해야하는데 이때 이 권한은 백엔드로부터 presigned url을 받음으로써 부여된다.

결론적으로 사용자가 이미지를 등록할 때 다음과 같이 진행된다.
1. 사용자가 이미지 등록하기 위해 이미지 선택
2. 프론트가 백엔드에게 s3에 업로드하기 위해 필요한 presigned-url과 앞으로 이미지를 사용할 때 쓰일 imageurl을 요청한다.
3. 필요한 url들을 응답으로 준다.
4. presigned-url을 가지고 s3에 이미지를 업로드한다.
5. 이미지를 성공적으로 s3에 업로드했다면 해당 이미지에 접근 가능한 Image url을 백엔드에게 api 요청에 담아 보낸다.
6. 백엔드는 이미지 데이터 자체가 아닌 이미지에 접근 가능한 url만 db에 저장한다.
7. 이미지를 보여주고싶을 때 서버로부터 이미지 url을 요청 후 받아서 사용할 수 있다.
대략적인 흐름은 위와 같은데 이를 react-quill과 같은 에디터 라이브러리에서 다룰 때는 몇가지 작업이 더 필요했다.

왜냐하면 quill의 이미지 추가 기능으로 이미지를 추가하면 위 사진처럼 이미지 태그와 함께 base64 형식으로 이미지가 생성되기 때문이었다. 그래서 파일 형식과 문자열 처리 등의 작업을 추가적으로 진행해야했다.
프로젝트 특성상 실제 코드를 자세히 올릴 수 없어서 아아아주 대략적으로 설명하겠다.
const uploadImagesAndGetUrls = async (base64Urls: any) => {
const s3Urls = [];
for (const base64Url of base64Urls) {
const file = base64ToFile(base64Url, 'image.jpg');
const { presignedUrl, imageUrl } =
await ImageUpload.getPresignedUrl(file);
await ImageUpload.imagesToS3(file, presignedUrl);
s3Urls.push('https://' + imageUrl);
}
return s3Urls;
};
base64ToFile함수를 생성해 base64형식을 변경함.
getPresignedUrl함수를 통해 서버로부터 url들을 받아옴.
받아온 presigned url을 통해 s3에 업로드하는 imagesToS3함수.
quill에 추가된 기존 base64형식의 이미지 태그들의 src를 s3url로 모두 변경하기 위해 s3urls 배열 사용.
각각의 함수 코드를 올릴 수는 없지만 로직을 이해한다면 구현하기 어려울 것이라고는 생각되지 않는다!