S3를 활용한 이미지 업로드 기능

ESH'S VELOG·2023년 10월 4일
1

웹페이지에 이미지를 업로드하여 게시판과 메뉴판을 시각적으로 볼 수 있도록 활용하기 위해 storage는 S3, 업로드 모듈 multer, 이미지 리사이징 패키지 sharp를 활용하여 기능 구현

  • Amazon S3란?

    Amazon Simple Storage Service의 줄임말로 쉽게 말해 파일을 저장할 수 있는 저장소로 데이터의 가용성과 보안, 성능을 제공한다. 매우 저렴한 storage로 활용도가 높다. 여기서 객체라고 하는 것은 저장소의 저장된 하나하나의 파일이다. bucket이라고 하는 디렉토리로 관리할 수 있다.

  • Multer 란?

    파일 업로드를 위해 사용되는 node.js의 middlware로 multipart(multipart/form-data)에서 동작한다.

  • sharp 란?

    node.js의 모듈로 빠른 속도로 큰 이미지를 작은 사이즈로 줄여주는 역할을 하며 JPEG, PNG, WebP, GIF, AVIF이미지를 지원한다.

  • 적용 순서
    1) AWS에 접속 후 S3검색하여 버킷을 만들고 설정
    2) 서버에 필요한 패키지 및 모듈 설치

    npm i -D @types/multer
    npm i aws-s
    npm i @aws-sdk/client-s3 @aws-sdk/s3-presigned-post
    npm i sharp

    3) src/aws/s3.service.ts 파일 생성
    4) src/aws/aws.module.ts 파일 생성
    5) multer를 사용하려는 router쪽에 Express.Multer.File type을 사용할 수 있고 import {Express} from 'express'에서 허용한다.

  • 적용 코드

  • s3.service.ts

import { Module } from '@nestjs/common';
import { S3Service } from './s3.service';

@Module({
  providers: [S3Service],
  exports: [S3Service],
})
export class AwsModule {}
  • aws.module.ts
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3'; // 여기 자동으로 안불러와짐
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import _ from 'lodash';
import sharp from 'sharp';

@Injectable()
export class S3Service {
  private readonly client: S3Client;
  private readonly region: string = this.configService.get<string>('REGION');
  private readonly bucket: string =
    this.configService.get<string>('BUCKET_NAME');
  constructor(private readonly configService: ConfigService) {
    this.client = new S3Client({
      region: this.region,
      credentials: {
        accessKeyId: this.configService.get<string>('AWS_ACCESS_KEY'),
        secretAccessKey: this.configService.get<string>('AWS_SECRET_KEY'),
      },
    });
  }

  async putObject(image: any) {
    const resizeImg = sharp(image.path);
    let { width, height } = await resizeImg.metadata();
    if (_.isUndefined(width)) {
      width = 1;
    }
    if (_.isUndefined(height)) {
      height = 1;
    }
    const maxWidth = 200;
    const maxHeight = 200;
    const ratio = Math.min(maxWidth / width, maxHeight / height);

    await this.client.send(
      new PutObjectCommand({
        Bucket: this.bucket,
        Key: image.filename,
        Body: await resizeImg
          .resize(Math.round(width * ratio), Math.round(height * ratio))
          .toBuffer(),
        ContentType: image.mimetype,
      }),
    );
    return `https://${this.bucket}.s3.${this.region}.amazonaws.com/${image.filename}`;
  }
}
profile
Backend Developer - Typescript, Javascript 를 공부합니다.

0개의 댓글