File upload

File upload

파일 μ—…λ‘œλ“œλ₯Ό μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄ NestλŠ” multer 미듀웨어λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. 이 λ―Έλ“€μ›¨μ–΄λŠ” μ™„μ „νžˆ ꡬ성 κ°€λŠ₯ν•˜λ©° μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μš”κ΅¬ 사항에 따라 μž‘λ™μ„ μ‘°μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

MulterλŠ” 주둜 파일 μ—…λ‘œλ“œμ— μ‚¬μš©λ˜λŠ” multipart/form-dataλ₯Ό μ²˜λ¦¬ν•˜κΈ°μœ„ν•œ λ―Έλ“€μ›¨μ–΄μž…λ‹ˆλ‹€.

warning κ²½κ³  MulterλŠ” λ©€ν‹° 파트 ( multipart/form-data)κ°€ μ•„λ‹Œ 폼을 μ²˜λ¦¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λ˜ν•œ 이 νŒ¨ν‚€μ§€λŠ” FastifyAdapter와 ν•¨κ»˜ μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

Basic example

단일 νŒŒμΌμ„ μ—…λ‘œλ“œν•˜κ³  싢을 λ•ŒλŠ” λ‹¨μˆœνžˆ FileInterceptor()λ₯Ό ν•Έλ“€λŸ¬μ— μ—°κ²°ν•œ λ‹€μŒ @UploadedFile()λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•˜μ—¬ μš”μ²­(request)μ—μ„œ 파일(file)을 κ°€μ Έμ˜΅λ‹ˆλ‹€.

@@filename()
@Post('upload')
@UseInterceptors(FileInterceptor('file'))
uploadFile(@UploadedFile() file) {
  console.log(file);
}
@@switch
@Post('upload')
@UseInterceptors(FileInterceptor('file'))
@Bind(UploadedFile())
uploadFile(file) {
  console.log(file);
}

info 힌트 FileInterceptor()λ°μ½”λ ˆμ΄ν„°λŠ” @nestjs/platform-express νŒ¨ν‚€μ§€μ—μ„œ 내보내고@UploadedFile()은 @nestjs/commonμ—μ„œ λ‚΄ λ³΄λƒ…λ‹ˆλ‹€.

FileInterceptor()λŠ”fieldName (νŒŒμΌμ„ λ³΄μœ ν•œ HTML ν˜•μ‹μ˜ ν•„λ“œλ₯Ό 가리킴)κ³Ό 선택적 options 객체의 두 인수λ₯Ό μ·¨ν•©λ‹ˆλ‹€. 이 MulterOptionsλŠ” multer μƒμ„±μžμ— μ „λ‹¬λœ 것과 λ™μΌν•©λ‹ˆλ‹€ (μžμ„Έν•œ λ‚΄μš©μ€ μ—¬κΈ°).

Array of files

파일 배열을 μ—…λ‘œλ“œν•˜κΈ° μœ„ν•΄ FilesInterceptor()λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. 이 μΈν„°μ…‰ν„°λŠ” μ„Έ κ°€μ§€ 인자λ₯Ό μ·¨ν•©λ‹ˆλ‹€. fieldName (λ™μΌν•˜κ²Œ μœ μ§€λ¨), maxCountλŠ” λ™μ‹œμ— μ—…λ‘œλ“œν•  수 μžˆλŠ” μ΅œλŒ€ 파일 수이며 선택적인 MulterOptions κ°μ²΄μž…λ‹ˆλ‹€. λ˜ν•œ request κ°μ²΄μ—μ„œ νŒŒμΌμ„ μ„ νƒν•˜κΈ° μœ„ν•΄ @UploadedFiles()λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€

@@filename()
@Post('upload')
@UseInterceptors(FilesInterceptor('files'))
uploadFile(@UploadedFiles() files) {
  console.log(files);
}
@@switch
@Post('upload')
@UseInterceptors(FilesInterceptor('files'))
@Bind(UploadedFiles())
uploadFile(files) {
  console.log(files);
}

info 힌트 FilesInterceptor() λ°μ½”λ ˆμ΄ν„°λŠ” @nestjs/platform-express νŒ¨ν‚€μ§€μ—μ„œ 내보내고@UploadedFiles()λŠ” @nestjs/commonμ—μ„œ λ‚΄ λ³΄λƒ…λ‹ˆλ‹€.

Multiple files

μ—¬λŸ¬ ν•„λ“œ (λͺ¨λ‘ λ‹€λ₯Έ ν‚€λ‘œ)λ₯Ό μ—…λ‘œλ“œν•˜κΈ° μœ„ν•΄ FileFieldsInterceptor() λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

@@filename()
@Post('upload')
@UseInterceptors(FileFieldsInterceptor([
  { name: 'avatar', maxCount: 1 },
  { name: 'background', maxCount: 1 },
]))
uploadFile(@UploadedFiles() files) {
  console.log(files);
}
@@switch
@Post('upload')
@Bind(UploadedFiles())
@UseInterceptors(FileFieldsInterceptor([
  { name: 'avatar', maxCount: 1 },
  { name: 'background', maxCount: 1 },
]))
uploadFile(files) {
  console.log(files);
}

Any files

λͺ¨λ“  ν•„λ“œλ₯Ό μ—…λ‘œλ“œν•˜λ €λ©΄ (λ‹€λ₯Έ ν‚€λ₯Ό μ‚¬μš©ν•˜μ§€λ§Œ μ•Œ ν•„μš”λŠ” μ—†μŠ΅λ‹ˆλ‹€) AnyFilesInterceptor()λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

@@filename()
@Post('upload')
@UseInterceptors(AnyFilesInterceptor())
uploadFile(@UploadedFiles() files) {
  console.log(files);
}
@@switch
@Post('upload')
@Bind(UploadedFiles())
@UseInterceptors(AnyFilesInterceptor())
uploadFile(files) {
  console.log(files);
}

Default options

multer λ™μž‘μ„ μ‚¬μš©μž μ •μ˜ν•˜κΈ° μœ„ν•΄ MulterModule을 등둝할 수 μžˆμŠ΅λ‹ˆλ‹€. 여기에 λ‚˜μ—΄λœ λͺ¨λ“  μ˜΅μ…˜μ„ μ§€μ›ν•©λ‹ˆλ‹€.

MulterModule.register({
  dest: '/upload',
});

Async configuration

λͺ¨λ“ˆ μ˜΅μ…˜μ„ 미리 μ „λ‹¬ν•˜λŠ” λŒ€μ‹  λΉ„λ™κΈ°μ‹μœΌλ‘œ μ „λ‹¬ν•˜λ €λŠ” κ²½μš°κ°€ μ’…μ’… μžˆμŠ΅λ‹ˆλ‹€. 이 경우, 비동기 데이터λ₯Ό μ²˜λ¦¬ν•˜λŠ” λ‹€μ–‘ν•œ 방법을 μ œκ³΅ν•˜λŠ” registerAsync() λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ‹­μ‹œμ˜€.

κ°€λŠ₯ν•œ 첫 번째 방법은 νŒ©ν† λ¦¬ κΈ°λŠ₯을 μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

MulterModule.registerAsync({
  useFactory: () => ({
    dest: '/upload',
  }),
});

λΆ„λͺ…νžˆ, 우리 νŒ©ν† λ¦¬λŠ” λ‹€λ₯Έ λͺ¨λ“  κ²ƒμ²˜λŸΌ ν–‰λ™ν•©λ‹ˆλ‹€ ( 비동기일 μˆ˜λ„ 있고 μ£Όμž…μ„ 톡해 μ˜μ‘΄μ„±μ„ μ£Όμž…ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€).

MulterModule.registerAsync({
  imports: [ConfigModule],
  useFactory: async (configService: ConfigService) => ({
    dest: configService.getString('MULTER_DEST'),
  }),
  inject: [ConfigService],
});

λ˜λŠ” νŒ©ν† λ¦¬ λŒ€μ‹  클래슀λ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

MulterModule.registerAsync({
  useClass: MulterConfigService,
});

μœ„μ˜ ꡬ성은 MulterModuleλ‚΄μ—μ„œ MulterConfigServiceλ₯Ό μΈμŠ€ν„΄μŠ€ν™” ν•˜κ³  이λ₯Ό ν™œμš©ν•˜μ—¬ μ˜΅μ…˜ 개체λ₯Ό λ§Œλ“­λ‹ˆλ‹€. MulterConfigServiceλŠ” MulterOptionsFactory μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•΄μ•Ό ν•©λ‹ˆλ‹€.

@Injectable()
class MulterConfigService implements MulterOptionsFactory {
  createMulterOptions(): MulterModuleOptions {
    return {
      dest: '/upload',
    };
  }
}

MulterModule 내에 MulterConfigServiceκ°€ μž‘μ„±λ˜λŠ” 것을 막고 λ‹€λ₯Έ λͺ¨λ“ˆμ—μ„œ κ°€μ Έμ˜¨ 제곡자λ₯Ό μ‚¬μš©ν•˜λ €λ©΄useExisting ꡬ문을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

MulterModule.registerAsync({
  imports: [ConfigModule],
  useExisting: ConfigService,
});

MulterModule은 κ°€μ Έμ˜¨ λͺ¨λ“ˆμ„ κ²€μƒ‰ν•˜μ—¬ 자체적으둜 μΈμŠ€ν„΄μŠ€ν™”ν•˜λŠ” λŒ€μ‹  이미 생성 된 ConfigServiceλ₯Ό 재 μ‚¬μš©ν•˜κΈ° μœ„ν•΄ κ°€μ Έμ˜¨ λͺ¨λ“ˆμ„ μ°ΎμŠ΅λ‹ˆλ‹€.

Last updated

Was this helpful?