웹페이지에 이미지를 업로드하여 게시판과 메뉴판을 시각적으로 볼 수 있도록 활용하기 위해 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 {}
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}`;
}
}