[Study] Image Upload Process

조혜인·2022년 8월 22일
post-thumbnail

📌 Image Upload Process

이미지를 업로드 하는 프로세스들 중 가장 기본적인 방식은 아래와 같다.

  • 브라우저에서 사용자가 업로드할 이미지 파일을 선택한다.
  • 브라우저에서 선택된 파일을 변수에 저장한다.
  • 브라우저에서는 파일 객체를 백엔드 서버에 업로드 요청을 한다.
  • 백엔드 서버에서는 작성된 API를 통해 전달받은 파일을 Cloud Storage에 저장한다.
  • Stroage에서는 파일을 저장한 결과로 해당 사진을 다운받을 수 있는 주소를 반환해준다.
  • 백엔드에서는 반환된 주소를 브라우저로 보내준다.
  • 이후에 브라우저에서 게시글을 작성하면 게시글의 내용과 함께 업로드한 파일의 URL을 담아 백엔드에게 게시물 등록 API를 요청한다.
  • 백엔드는 요청된 API를 이용하여 전달받은 정보들을 DB에 저장한다. 이때 서비스의 구조에 따라서 게시물 정보 테이블에 업로드된 파일의 URL이 저장될 수도 있고, 이미지 테이블을 따로 가지고 있다면 해당 테이블에 URL이 저장될 수 있다.

Example

다음은 GCP에 전달받은 이미지 파일을 저장하는 로직이다.

export class FilesService {
  async upload({ files }) {

    const waitedFiles = await Promise.all(files);

    /* 이미지를 저장할 GCP bucket과 연결 */
    const bucket = process.env.GOOGLE_BUCKET;
    const storage = new Storage({
      projectId: process.env.GOOGLE_BUCKET_PROJECT_ID,
      keyFilename: process.env.GOOGLE_BUCKET_KEY_FILENAME,
    }).bucket(process.env.GOOGLE_BUCKET);

    /* 전달받은 이미지들을 업로드하기 */
    const results = await Promise.all(
      waitedFiles.map(
        (el) =>
          new Promise((resolve, reject) => {
            el.createReadStream()
              .pipe(storage.file(el.filename).createWriteStream())
              .on('finish', () => resolve(`${bucket}/${el.filename}`))
              .on('error', () => reject('실패!!'));
          }),
      ),
    );

    return results;
  }
}

1개 이상의 이미지 파일을 브라우저로부터 전달받았다면 먼저 Promise.all()을 이용하여 waitedFiles로 넣어주어 파일의 정보를 저장한다. 이후 저장할 GCP와 연결을 해주고 이미지 저장 시간을 절약하기 위하여 Promise.all()로 이미지들을 Storage에 저장한다. 각각 들어온 파일 정보들을 createReadStream()으로 읽어들이고 해당 파일 정보를 pipe안에 넣어주어 storage에 저장시킨다. 만약 저장에 성공하였다면 resolve()가 호출되고 실패하였다면 reject()가 호출된다.

그런데 우리가 여기서 조금 더 생각해보면, 요즘은 브라우저를 다양한 기기에서 접속할 수 있다. PC가 될 수도 있고 핸드폰 혹은 태블릿에서 브라우저를 열 수 있다. 그럴 때마다 제공되는 서비스에서는 해당 기기에 맞게 이미지의 크기를 조정하여 보여줄 수 있어야 한다. 이럴 때에는 sharp라는 라이브러리를 사용하여 필요한 사이즈로 썸네일을 생성하여 저장해줄 수 있다.

profile
코딩은 역시 재밌군

0개의 댓글