[NestJS]AWS S3 Uploader 모듈 만들기

도도·2021년 8월 1일
1

기술Velog

목록 보기
3/28

AWS S3 Uploader 모듈 만들기

과정

  1. S3 IAM 사용자 생성
  2. 엑세스키,비밀키 env 설정
  3. 버킷 만들기
  4. 파일 업로드
  5. 파일 삭제

1. S3 IAM 사용자 생성

  • AWS IAM 에서 사용자를 추가 한다.

  • aws-sdk로 AWS S3의 자원에 접근하게 되므로,
    aws 엑세스 유형은 프로그래밍 방식 엑에스 이다.

  • 사용자의 권한 설정부분에서는
    AmazonS3FullAcess로 권한을 부여한다. (기존정책연결)

  • 결과: 엑세스ID, 비밀 액세스 키

2. 엑세스키,비밀키 env 설정

.env.dev 에 추가하여 configServce에서 관리하도록 한다.

AWS_CONFIG_REGION = ap-northeast-2
AWS_S3_BUCKET_NAME = test
AWS_S3_ACCESS_KEY = xxx
AWS_S3_SECRET_ACCESS_KEY = xxx

3. 버킷 만들기

  async __createBucket() {
    return await this.S3.createBucket({
      Bucket: this.buketName,
    }).promise();
  }

4. 파일 업로드

  async uploadS3(file: Express.Multer.File, folder?: string) {
    const Key = `${Date.now()}${file.originalname}`;
    folder = folder ? folder : 'common';
    try {
      console.log(`${this.buketName}/${folder}`);
      const result = await this.S3.putObject({
        Bucket: `${this.buketName}/${folder}`,
        ACL: this.ACL,
        Key,
        Body: file.buffer,
      }).promise();
      return {
        ok: true,
        ETag: result.ETag,
        Key,
        url: this.__makePublicUrl(`${folder}/${Key}`),
      };
    } catch (error) {
      this.logger.error(error);
      return { ok: false };
    }
  }

5. 파일 삭제

  async deleteS3(Key: string) {
    try {
      await this.S3.deleteObject({
        Bucket: this.buketName,
        Key,
      }).promise();
      return { ok: true };
    } catch (error) {
      this.logger.error(error);
    }
  }

결과:모듈

import { Module } from '@nestjs/common';
import { UploadController } from './upload.controller';
import { UploadService } from './upload.service';

@Module({
  imports: [],
  providers: [UploadService],
  controllers: [UploadController],
  exports: [],
})
export class UploadModule {}

결과:서비스

import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as AWS from 'aws-sdk';
@Injectable()
export class UploadService {
  private readonly S3: AWS.S3;
  private readonly region: string;
  private readonly buketName: string;
  private readonly ACL: string;
  private readonly logger = new Logger(UploadService.name);

  constructor(private readonly configService: ConfigService) {
    // (1) Region + Key 설정
    AWS.config.update({
      credentials: {
        accessKeyId: configService.get('AWS_S3_ACCESS_KEY'),
        secretAccessKey: configService.get('AWS_S3_SECRET_ACCESS_KEY'),
      },
      region: configService.get('AWS_CONFIG_REGION'),
    });
    // (2) S3객체,엑세스레밸 , 버킷이름+지역
    this.S3 = new AWS.S3();
    this.buketName = configService.get('AWS_S3_BUCKET_NAME');
    this.region = configService.get('AWS_CONFIG_REGION');
    this.ACL = 'public-read';

    // this.deleteS3('banner/1627107563231robot-dev.png');
  }

  // 버킷 생성
  async __createBucket() {
    return await this.S3.createBucket({
      Bucket: this.buketName,
    }).promise();
  }
  // img src 생성
  __makePublicUrl(dest) {
    return `https://${this.buketName}.s3.${this.region}.amazonaws.com/${dest}`;
  }
  // (1) (common) 폴더 업로드
  async uploadS3(file: Express.Multer.File, folder?: string) {
    const Key = `${Date.now()}${file.originalname}`;
    folder = folder ? folder : 'common';
    try {
      console.log(`${this.buketName}/${folder}`);
      const result = await this.S3.putObject({
        Bucket: `${this.buketName}/${folder}`,
        ACL: this.ACL,
        Key,
        Body: file.buffer,
      }).promise();
      return {
        ok: true,
        ETag: result.ETag,
        Key,
        url: this.__makePublicUrl(`${folder}/${Key}`),
      };
    } catch (error) {
      this.logger.error(error);
      return { ok: false };
    }
  }

  // (2) icon 폴더 업로드
  async uploadS3Icon(file: Express.Multer.File) {
    const folder = 'icon';
    return this.uploadS3(file, folder);
  }
  // (3) 배너 폴더 업로드
  async uploadS3Banner(file: Express.Multer.File) {
    const folder = 'banner';
    return this.uploadS3(file, folder);
  }

  // (1) 오브젝트 삭제
  async deleteS3(Key: string) {
    try {
      await this.S3.deleteObject({
        Bucket: this.buketName,
        Key,
      }).promise();
      return { ok: true };
    } catch (error) {
      this.logger.error(error);
    }
  }
  // (2) 아이콘 삭제
  async deleteS3Icon(Key: string) {
    return this.deleteS3(`icon/${Key}`);
  }
  // (3) 배너 삭제
  async deleteS3Banner(Key: string) {
    return this.deleteS3(`banner/${Key}`);
  }
}

//https://algoridang.s3.ap-northeast-2.amazonaws.com/1627105957873page_fault.gif
//https://algoridang.s3/.ap-northeast-2.amazonaws.com/1627105957873page_fault.gif

결과:컨트롤러

import {
  Controller,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { UploadService } from './upload.service';

@Controller('/api/upload')
export class UploadController {
  constructor(private readonly uploadService: UploadService) {}
  @Post('')
  @UseInterceptors(FileInterceptor('file'))
  async uploadFile(@UploadedFile() file: Express.Multer.File) {
    // await this.uploadService.uploadS3Banner(file);
    // await this.uploadService.uploadS3Icon(file);
    return this.uploadService.uploadS3(file);
  }
}
profile
프론트 주력의 JS 개발자 입니다.! Node.js, React, NestJS 에 관심이 많습니다.

0개의 댓글