ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • AWS-SDK를 사용하여 S3에 업로드
    Infra/클라우드 2022. 8. 1. 13:56

    npm Dependency aws-sdk

    AWS에 있는 모든 솔루션이나 서비스들을 NodeJS 직접 사용하고 컨트롤 할 수 있도록 AWS자체에서 제공해주는 package이다. 특히 S3 라이브러리를 사용할 것이다.

     

    @Post('upload')
      @UseInterceptors(FileInterceptor('image'))
      async uploadMediaFile(@UploadedFile() file: Express.Multer.File) {
        console.log(file);
      }

     

    FileInterceptor('image')

    의미 => Post body를 통해서 data를 백엔드에 전달할 시 form-data에서  key가 'image'인 key-value를 통해서 file 정보를 넘긴다는 의미이다.

     

    해당 Interceptor를 사용하는 메서드는 @UploadedFile() 데코레이터를 통해서 file 정보를 받을 수 있게 된다.

     


    uploadMediaFile와 매치된 api를 request 했을 시

     @UploadedFile()통해 메서드에 전단된 인자file의 console출력 결과이다.

     

    file자체를 AWS clouding 기술을 통해서 S3에 upload

     


    AwsService

     

    constructor

     constructor(private readonly configService: ConfigService) {
        this.awsS3 = new AWS.S3({
          accessKeyId: this.configService.get('AWS_S3_ACCESS_KEY'), // process.env.AWS_S3_ACCESS_KEY
          secretAccessKey: this.configService.get('AWS_S3_SECRET_KEY'),
          region: this.configService.get('AWS_S3_REGION'),
        });
        this.S3_BUCKET_NAME = this.configService.get('AWS_S3_BUCKET_NAME'); // nest-s3
      }

     

    생성자에서 ConfigService를 의존성 주입(DI) 받아서 생성하고 있다. ConfigService는 해당 service class가 속한 module.ts의 @Module({}) 데코레이터의 imports를 통해 등록을 하면 .env 같은 file을 읽을수 있게 된다.

     

     

    this.awsS3

    this.awsS3 = new AWS.S3({
          accessKeyId: this.configService.get('AWS_S3_ACCESS_KEY'), // process.env.AWS_S3_ACCESS_KEY
          secretAccessKey: this.configService.get('AWS_S3_SECRET_KEY'),
          region: this.configService.get('AWS_S3_REGION'),
        });

     configService 객체의 각각의 환경변수이 다 저장되어 있다. 그래서  ConfigService 자체를 DI 받아서 위 코드와 같이 this.configService.get()을 통해서 환경변수를 가져 올 수있다.

     

    awsS3라는 인스턴스 객체를 하나 할당을 받을 것인데, 해당 인스턴스는 AWS라는 모듈안에 S3라는 class를 통해서 생성한다.

     

    그리고 생성시에 속성으로 accessKeyId,secretAccessKey, region 를 갖는 설정 객체를  넣어준다.

     

    마지막으로 생성자에서 S3_BUCKET_NAME도 설정해 준다.


    uploadFileToS3()

    file을 upload하는 함수이다.

    async uploadFileToS3(
        folder: string,
        file: Express.Multer.File,
      ): Promise<{
        key: string;
        s3Object: PromiseResult<AWS.S3.PutObjectOutput, AWS.AWSError>;
        contentType: string;
      }> {
        try {
          const key = `${folder}/${Date.now()}_${path.basename(
            file.originalname,
          )}`.replace(/ /g, '');
    
          const s3Object = await this.awsS3
            .putObject({
              Bucket: this.S3_BUCKET_NAME,
              Key: key,
              Body: file.buffer,
              ACL: 'public-read',
              ContentType: file.mimetype,
            })
            .promise();
          return { key, s3Object, contentType: file.mimetype };
        } catch (error) {
          throw new BadRequestException(`File upload failed : ${error}`);
        }
      }

     

    1.parameter

     uploadFileToS3(folder: string,file: Express.Multer.File,){}

    1.parameter => forder : S3에 저장이 될 때 어떤 폴더에 저장이 될지 지정하는 인자이다.

    엄밀히 말하면 S3에는 폴더 개념이 아니라 link 개념을 가지고 있다.

     

    2.parameter => file : controller를 통해 넘어오는 Express.Multer.File 타입의 data이다.

     

    2.return 값

    Promise<{
        key: string;
        s3Object: PromiseResult<AWS.S3.PutObjectOutput, AWS.AWSError>;
        contentType: string;
      }>
      ...
      return { key, s3Object, contentType: file.mimetype };
    • key : S3에 저장이 되고 나서, S3저장한 key를 의미한다.
    • contentType : image 혹은 video 등이 될 수 있다.

     

    3.const key

     const key = `${folder}/${Date.now()}_${path.basename(
            file.originalname,
          )}`.replace(/ /g, '');
    • file.originalname = 두번째 인자 file.의 속성 값으로 upload된 file의 이름부터 확장자까지 불러온다.
    • replace(/ /g, '') = url safe하기 위해 url 뒤에 들어가는 공백을 지워주는 역학을 한다. 첫번째 인자는 정규표현식이다.

     

    *replace() = replace()라는 메서드는 문자열 data에 대해서 특정한 글자(character)를 다른 글자로 바꿔준다.

     

    4.const s3Object

     const s3Object = await this.awsS3
            .putObject({
              Bucket: this.S3_BUCKET_NAME,
              Key: key,
              Body: file.buffer,
              ACL: 'public-read',
              ContentType: file.mimetype,
            })
            .promise();

     

     

     

    5.putObject()

    try {
          const key = `${folder}/${Date.now()}_${path.basename(
            file.originalname,
          )}`.replace(/ /g, '');
    
          const s3Object = await this.awsS3
            .putObject({
              Bucket: this.S3_BUCKET_NAME,
              Key: key,
              Body: file.buffer,
              ACL: 'public-read',
              ContentType: file.mimetype,
            })
            .promise();
          return { key, s3Object, contentType: file.mimetype };
        } catch (error) {
          throw new BadRequestException(`File upload failed : ${error}`);
        }

    생성자에서 생성한 인스턴스 변수 awsS3의 인스턴스 멤버 메서드로 객체를 생성한다. 설정 객체로 각각 속성 값을 지정한다. 

    •  Key : 어떤 이름을 저장될지 설정하는 속성
    • Body : file의 buffer 값을 넣는다.

    Promise에 담겨서 반환하기 위해 마지막에 promise 메서드를 추가한다.  값이 성공적으로 return이 되면, upload 된 filedl 정상적으로 S3에 저장된 것이다.


    DeleteS3Object()

    file을 delete하는 함수이다.

    async deleteS3Object(
        key: string,
        callback?: (err: AWS.AWSError, data: AWS.S3.DeleteObjectOutput) => void,
      ): Promise<{ success: true }> {
        try {
          await this.awsS3
            .deleteObject(
              {
                Bucket: this.S3_BUCKET_NAME,
                Key: key,
              },
              callback,
            )
            .promise();
          return { success: true };
        } catch (error) {
          throw new BadRequestException(`Failed to delete file : ${error}`);
        }
      }

    deletObject()

    delete 역시 awsS3인스턴스의 멤버 메서드를 사용하여, S3에 올라간 특정 file을 삭제할 수 있다. 

     

    삭제할 s3Object에 bucket name과 key를 속성으로 갖는 object를  첫번째 인자로 넣고, 두번째 인자로 정상적으로 삭제가 진행 되지 않을 시 발생할 error와 정상적으로 삭제가 되었을때 받게되는 data를 가진 callback 함수를 넣는다.

     

    S3의 file 삭제

    저장된 key를 지우고 싶다면,  S3에 file을 upload할 시에 반환 받은 key값을 DeleteS3Object()메서드에 넣으면 된다.

    DB의 image field에 특정file과 매칭된 key값을 저장해둔다. key값만 알면 해당하는 S3위치로 가서 file정보들을 다 가져올 수 있다.

     

     


    getAwsS3FileUrl()

    public getAwsS3FileUrl(objectKey: string) {
        return `https://${this.S3_BUCKET_NAME}.s3.amazonaws.com/${objectKey}`;
      }

    file이 어디에 저장되어 있는지를 알려주는 매칭 key를 인자 objectKey로 받아 file이 저장된 전체 url 소스 return한다.


    Amazon S3

    [출처 -https://www.inflearn.com/course/%ED%83%84%ED%83%84%ED%95%9C-%EB%B0%B1%EC%97%94%EB%93%9C-%EB%84%A4%EC%8A%A4%ED%8A%B8/dashboard]

    댓글

Designed by Tistory.