본문 바로가기

과거공부모음

20230221 TIL - nestjs 이미지 업로드

Today I learned

nestjs를 이용해서 이미지를 업로드 하는 작업을 진행했다

expressjs에서는 multer패키지를 사용해서 이미지를 업로드했다

nestjs에서는 multer를 기본적으로 nestjs에 내장되어 있다고 한다 @nestjs/platform-express 패키지를 사용하자

작업을 진행하기 전 안전한 개발을 위해 설치해야하는 파일이 있다

npm install @types/multer --save-dev

 

 

image.module에다가 설정을 진행해줘야 한다

@Module({
  imports: [
    MulterModule.registerAsync({
      useFactory: multerOptionsFactory,
    }),
  ],
  controllers: [ImageController],
  providers: [ImageService],
})
export class ImageModule {}

register를 사용하지 않고 registerAsync를 사용하는 이유는 다음 작업에서 AWS S3와 연동하기 위해서 configService를 inject하기 위해서다

 

 

multerOptionsFactory를 만들자 처음은 디스크 방식의 업로드로 진행했다

import { MulterOptions } from '@nestjs/platform-express/multer/interfaces/multer-options.interface';
import { diskStorage, memoryStorage } from 'multer';
import { extname, basename } from 'path';

export const multerOptionsFactory = (): MulterOptions => {
  return {
    storage: diskStorage({
			destination: (request, file, callback) => {
			      const uploadPath = 'uploads';
			      if (!existsSync(uploadPath)) {
			        mkdirSync(uploadPath);
			      }
			      callback(null, uploadPath);
    },
      filename(req, file, cb) {
        const imageExt = extname(file.originalname);
        const imageBasename = basename(file.originalname, imageExt);

        cb(null, `${imageBasename}_${Date.now()}${imageExt}`);
      },
    }),
  };
};

storage: diskStorage를 사용할 때 destination 옵션을 사용하면 미들웨어를 지나가면서 바로 업로드가 진행이 된다 이 부분이 편하기는 하지만 내가 생각하는 동작방식과 어울리지 않는다

나는 이미지와 같이 요청들어오는 데이터들이 DB에 안정적으로 저장이 되고 요청이 정상적으로 작동을 했다면 마지막에 이미지를 저장하고 싶었다

저번 작업에서는 요청이 들어오고 예외처리가 진행되었는데 이미지는 저장이 되어서 다시 삭제하는 문제가 있었기 때문에 이 부분에서 꼭 해결하고 싶었다

그래서 destination옵션을 사용하지 않고 진행을 해보았다 사용하지 않으면 운영체제의 시스템 임시 파일을 저장하는 기본 디렉터리에 임시 저장이 된다

 

 

이제 image.controller를 가보자

@Controller('image')
export class ImageController {
  constructor(private readonly imageService: ImageService) {}

  @Post('upload')
  @UseInterceptors(FileInterceptor('file'))
  uploadFile(@UploadedFile() file: Express.Multer.File) {
    return this.imageService.uploadImage(uuid(), file);
  }
}

@UseInterceptors(FileInterceptor(’file’) 이 부분에서 이미지를 보낼 때 key 값으로 지정한 이름을 잘 적용해 주어야 한다

나는 파일을 service에서 처리하기 때문에 요청받은 파일을 service에 보낸다

 

 

다음 image.service에 가보자

@Injectable()
export class ImageService {
  uploadImage(userId: string, file: Express.Multer.File) {
    if (!file) {
      throw new BadRequestException('이미지가 존재하지 않습니다.');
    }

    const uploadFilePath = `uploads/${userId}`;

    console.log(existsSync(uploadFilePath));
    if (!existsSync(uploadFilePath)) {
      // uploads 폴더가 존재하지 않을시, 생성합니다.
      mkdirSync(uploadFilePath, { recursive: true });
    }

    const fileName = Date.now() + extname(file.originalname);
    const uploadPath = __dirname + `/../../${uploadFilePath + '/' + fileName}`;

    writeFileSync(uploadPath, file.path);
  }
}

이미지의 이름과 업로드 경로를 지정하고 writeFileSync를 이용해서 임시 저장소에 있는 파일을 저장하는 방식으로 진행을 했는데 문제가 발생했다 이미지가 저장은 되는데 이미지가 깨진건지 로드가다

writeFileSync를 조금 더 알아본 결과 data에 들어가는 것들이 파일에 기록될 문자열이나 Buffer, TypedArray, DataView라고 한다 그래서 file.path를 readFileSync로 파일을 읽어서 buffer정보를 반환시켜 사용해보기로 했다

writeFileSync(uploadPath, readFileSync(file.path));

이렇게 사용하면 이미지가 이상하게 저장되지 않고 정상적으로 저장이 된다!

buffer를 이용해서 저장하기 때문에 임시파일을 저장하고 그 저장된 임시파일을 읽어서 buffer를 다시 사용하는 것 보다 임시파일을 생성하기 않고 메모리에 있는 정보를 사용하는 방식이 더 효율적일 수 있겠다는 생각이 들어서 메모리를 사용하는 방식으로도 진행해 보았다

 

 

multer.options.factory.ts 파일로 돌아가서 multerOptionsFactory를 수정해보자

return {
    storage: memoryStorage(),
    limits: { fileSize: 10 * 1024 * 1024 }, // 10MB로 크기를 제한
  };

storage: memoryStorage를 사용하는 방식이다

 

 

image.service.ts 파일을 가서 writeFileSync를 수정하자

writeFileSync(uploadPath, file.buffer);

이 방식을 사용해도 정상적으로 작동을 한다

 

 

 

참고 사이트 / 블로그

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Progamming), FP (Functional Programming), and FRP (Functional Reac

docs.nestjs.com

 

[Nest.js] Nest.js API 만들기 (11) - 파일 업로드(Multer)

- 개요 안녕하세요. 이번 시간에는 파일 업로드를 진행해 보겠습니다. Multer를 사용해서 파일 업로드를 진행해보겠습니다. Multer는 Node.js에서 대표적인 파일 업로드 라이브러리입니다. Nest.js 공식

any-ting.tistory.com

 

NestJS 파일 업로드하기(1) | Kkiri Blog

NestJS에서 파일 업로드하는 것은 expre...

devkkiri.com

 

Node.js | fs.writeFileSync() Method - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

node.js에서 파일업로드 처리시 임시파일 생성하지 않기

웹 브라우저에서 파일 업로드를 처리하는 가장 일반적인 방법은 multipart/form-data를 이용해서 http post메소드의 body에 파일데이터를 함께 전송하는 방법이다. 대부분의 웹애플리케이션의 경우 이렇

ivorycirrus.github.io

 

[Node] 이미지파일 base64로 encode, decode 하기

Buffer를 사용 const fs = require('fs'); let readFile = fs.readFileSync('./test.jpg'); //이미지 파일 읽기 let encode = Buffer.from(readFile).toString('base64'); //파일 인코딩 let makeEncodeFile = fs.writeFileSync('./encodeFile', encode) //인

minu0807.tistory.com