본문 바로가기
nestJS

NestJS | Multer, Static File Serving

by 리잼 2024. 11. 26.
반응형

Multer

Multer는 Node.js에서 파일 업로드를 처리하는 미들웨어로, Express와 NestJS 같은 프레임워크와 함께 자주 사용된다

멀티파트 폼 데이터(multipart/form-data)를 처리하며, 업로드된 파일을 요청 객체(req.file 또는 req.files)에 추가해준다

이를 통해 서버에서 업로드된 파일을 쉽게 다룰 수 있다

특징

  1. 멀티파트 폼 데이터 지원
    • Multer는 일반적인 JSON 또는 URL-encoded 데이터가 아닌, 파일과 데이터를 함께 전송하는 멀티파트 폼 데이터를 처리한다.
  2. 스토리지 옵션 제공
    • Multer는 업로드된 파일을 처리할 위치를 설정할 수 있다.
      • 메모리 저장소: 파일이 메모리에 버퍼 형태로 저장
      • 디스크 저장소: 파일이 지정된 디렉토리에 저장
  3. 파일 필터링
    • 업로드된 파일의 형식, 크기, 이름 등을 필터링하여 원하는 파일만 처리할 수 있다.
  4. 다중 파일 업로드 지원
    • Multer는 한 번에 여러 파일을 업로드할 수 있도록 지원함

설치 명령어

npm i multer @types/multer

 

Multer 설정 코드

common.mudule.ts

import { BadRequestException, Module } from '@nestjs/common';
import { CommonService } from './common.service';
import { CommonController } from './common.controller';
import { MulterModule } from '@nestjs/platform-express';
import { extname } from 'path';
import * as multer from 'multer';
import { POST_IMAGE_PATH, TEMP_FOLDER_PATH } from './const/path.const';
import { v4 as uuid } from 'uuid';
import { AuthModule } from '../auth/auth.module';
import { UsersModule } from '../users/users.module';

@Module({
  imports: [
    AuthModule,
    UsersModule,
    MulterModule.register({
      // 파일 크기 제한
      limits: {
        // 바이트 단위로 입력
        fileSize: 10000000,
      },
      fileFilter: (req, file, cb) => {
        /*
      cb(에러 | bool)
      첫번쨰 파라미터는 에러가 있을경우 에러를 넣어줌
      두번째는 파일을 받을지 말지 boolean 을 넣어줌
       */
        // xxx.jpg -> .jpg
        const ext = extname(file.originalname);

        if (ext !== '.jpg' && ext !== '.jpeg' && ext !== '.png') {
          return cb(new BadRequestException('jpg, jpeg, png 파일만 업로드 가능'), false);
        }
        return cb(null, true);
      },
      storage: multer.diskStorage({
        destination: (req, file, cb) => {
          cb(null, TEMP_FOLDER_PATH);
        },
        filename: (req, file, cb) => {
          cb(null, `${uuid()}${extname(file.originalname)}`);
        },
      }),
    }),
  ],
  controllers: [CommonController],
  providers: [CommonService],
  exports: [CommonService],
})
export class CommonModule {}

코드 설명

1. 파일 업로드 크기 제한

limits: {
  fileSize: 10000000, // 최대 파일 크기: 10MB (10,000,000 바이트)
},
  • 업로드 가능한 파일의 최대 크기를 제한
  • fileSize가 초과되면 BadRequestException 과 같은 에러가 발생하며 파일 업로드가 중단됨

2. 파일 필터링

fileFilter: (req, file, cb) => {
  const ext = extname(file.originalname);

  if (ext !== '.jpg' && ext !== '.jpeg' && ext !== '.png') {
    return cb(new BadRequestException('jpg, jpeg, png 파일만 업로드 가능'), false);
  }
  return cb(null, true);
},
  • fileFilter 는 파일이 업로드되기 전에 파일의 유효성을 검증하는 역할을 함
  • file.originalname의 확장자를 추출하여 .jpg, .jpeg, .png 형식만 허용함
  • 다른 파일 형식이 업로드되면 BadRequestException 을 반환하며 업로드를 중단

3. 저장소 설정

storage: multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, TEMP_FOLDER_PATH);
  },
  filename: (req, file, cb) => {
    cb(null, `${uuid()}${extname(file.originalname)}`);
  },
}),
  • **storage**는 업로드된 파일이 저장되는 위치와 이름을 설정함

3-1. 저장위치

destination: (req, file, cb) => {
  cb(null, TEMP_FOLDER_PATH);
},
  • TEMP_FOLDER_PATH에 파일을 저장함

3-2. 파일이름

filename: (req, file, cb) => {
  cb(null, `${uuid()}${extname(file.originalname)}`);
},
  • 파일 이름은 **UUID (Universally Unique Identifier)**를 생성하여 설정함
    • 예: 123e4567-e89b-12d3-a456-426614174000.jpg
  • 확장자는 원본 파일 이름에서 추출된 값(extname(file.originalname))을 그대로 사용함
    • 예: .jpg, .png

4. 예외 처리

return cb(new BadRequestException('jpg, jpeg, png 파일만 업로드 가능'), false);
  • 업로드 제한 조건을 만족하지 않는 경우 BadRequestException을 발생시킨다.

5. 업로드 결과

업로드 성공 / 실패

 

게시물 등록 Multer 적용 코드

post.controller.ts

  @Post()
  @UseGuards(AccessTokenGuard)
  @UseInterceptors(FileInterceptor('image'))
  postPost(
  	@User('id') userId: number,
  	@Body() body: CreatePostDto,
    @UploadedFile() file?: Express.Multer.File
    ) {
    return this.postsService.createPost(userId, body, file?.filename);
  }
  • @UseInterceptors(FileInterceptor('image'))
    • Multer를 사용하여 파일 업로드를 처리
    • 클라이언트가 전송한 파일이 HTTP 요청에서 image라는 이름의 필드로 첨부됨

 

  • @UploadedFile() file?: Express.Multer.File
    • 업로드된 파일 정보를 Multer에서 가져옴
    • 파일이 업로드되지 않았다면 file은 undefined 가 됨

 

post.service.ts

컨트롤러에서 이미지 정보를 전달받아 요청을 처리한다.


Static File Serving

NestJS에서 정적 파일을 제공하기 위해 사용하는 모듈
애플리케이션이 지정된 디렉토리의 파일을 HTTP 요청으로 클라이언트에 서빙할 수 있다

 

설치 명령어

npm i @nestjs/serve-static

 

사용 방법

app.module.ts

// imports: [] 에 추가
ServeStaticModule.forRoot({
      // 4022.jpg
      // http://localhost:3000/public/posts/4022.jpg
      // http://localhost:3000/posts/4022.jpg
      rootPath: PUBLIC_FOLDER_PATH,
      serveRoot: '/public',
    }),

 

  • rootPath
    • 정적 파일이 저장된 디렉토리의 절대 경로를 지정
    • 예: PUBLIC_FOLDER_PATH가 /uploads로 설정된 경우, /uploads 디렉토리 내의 파일을 서빙하게 된다.
  • serveRoot
    • 정적 파일에 접근하기 위한 URL 경로(prefix)를 지정
    • 예: serveRoot: '/public'으로 설정하면, 정적 파일은 http://<호스트>:<포트>/public 경로를 통해 접근할 수 있다.

동작 원리

예시 동작

1. 디렉토리 구조

/uploads

├── posts

│   ├── 4022.jpg

│   ├── 1234.png

 

  • PUBLIC_FOLDER_PATH가 /uploads로 설정되었다고 가정.
  1. 정적 파일 요청
    • 클라이언트가 http://localhost:3000/public/posts/4022.jpg로 요청을 보냄.
  2. 파일 매핑
    • 서버는 /uploads/posts/4022.jpg 경로에서 파일을 검색
    • 파일이 존재한다면 클라이언트로 해당 파일을 반환
  3. 결과
    • 클라이언트는 브라우저 또는 기타 클라이언트에서 4022.jpg 이미지를 확인할 수 있다

 

 

반응형

'nestJS' 카테고리의 다른 글

NestJS | Class Validator, Transformer  (1) 2024.11.20
NestJS | Guard  (0) 2024.11.20
NestJS | Pipe  (0) 2024.11.20
NestJS | TypeORM Table Inheritance  (0) 2024.11.12
NestJS | TypeORM Entity Embedding  (2) 2024.11.12