Maison  >  Article  >  interface Web  >  Rationalisez les téléchargements de fichiers dans NestJS : analyse efficace en mémoire pour CSV et XLSX sans stockage sur disque

Rationalisez les téléchargements de fichiers dans NestJS : analyse efficace en mémoire pour CSV et XLSX sans stockage sur disque

DDD
DDDoriginal
2024-10-01 06:26:03355parcourir

Analyse de fichiers sans effort dans NestJS : gérez les téléchargements CSV et XLSX en mémoire pour plus de vitesse, de sécurité et d'évolutivité

Introduction

Gérer les téléchargements de fichiers dans une application Web est une tâche courante, mais gérer différents types de fichiers et s'assurer qu'ils sont traités correctement peut s'avérer difficile. Souvent, les développeurs doivent analyser les fichiers téléchargés sans les enregistrer sur le serveur, ce qui est particulièrement important pour réduire les coûts de stockage du serveur et garantir que les données sensibles ne sont pas inutilement conservées. Dans cet article, nous passerons en revue le processus de création d'un module NestJS personnalisé pour gérer les téléchargements de fichiers spécifiquement pour les fichiers CSV et XLS/XLSX, et nous analyserons ces fichiers en mémoire à l'aide des flux Node.js, afin qu'aucun fichier statique ne soit généré. créé sur le serveur.

Pourquoi NestJS ?

NestJS est un framework Node.js progressif qui exploite TypeScript et fournit une architecture d'application prête à l'emploi qui vous permet de créer des applications hautement testables, évolutives, faiblement couplées et faciles à maintenir. En utilisant NestJS, nous pouvons profiter de sa structure modulaire, de son puissant système d'injection de dépendances et de son vaste écosystème.

Étape 1 : Mise en place du projet

Avant de plonger dans le code, mettons en place un nouveau projet NestJS. Si vous ne l'avez pas déjà fait, installez la CLI NestJS :

npm install -g @nestjs/cli

Créez un nouveau projet NestJS :

nest new your-super-name

Naviguez dans le répertoire du projet :

cd your-super-name

Étape 2 : Installation des packages requis

Nous devrons installer des packages supplémentaires pour gérer le téléchargement et l'analyse des fichiers :

npm install @nestjs/platform-express multer exceljsfile-type
  • Multer : un middleware pour gérer les données multipart/form, qui est principalement utilisé pour le téléchargement de fichiers.
  • Exlesjs : Une bibliothèque puissante pour analyser les fichiers CSV/XLS/XLSX.
  • File-Type : Une bibliothèque pour détecter le type de fichier d'un flux ou d'un tampon.

Étape 3 : Création du moteur de stockage Multer sans enregistrer de fichiers

Pour personnaliser le processus de téléchargement de fichiers, nous allons créer un moteur de stockage Multer personnalisé. Ce moteur garantira que seuls les fichiers CSV et XLS/XLSX sont acceptés, les analysera en mémoire à l'aide des flux Node.js et renverra les données analysées sans enregistrer aucun fichier sur le disque.

Créez un nouveau fichier pour notre moteur :

import { PassThrough } from 'stream';
import * as fileType from 'file-type';
import { BadRequestException } from '@nestjs/common';
import { Request } from 'express';
import { Workbook } from 'exceljs';
import { createParserCsvOrXlsx } from './parser-factory.js';

const ALLOWED_MIME_TYPES = [
  'text/csv',
  'application/vnd.ms-excel',
  'text/comma-separated-values',
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  'application/vnd.ms-excel',
] as const;

export class CsvOrXlsxMulterEngine {
  private destKey: string;
  private maxFileSize: number;
  constructor(opts: { destKey: string; maxFileSize: number }) {
    this.destKey = opts.destKey;
    this.maxFileSize = opts.maxFileSize;
  }
  async _handleFile(req: Request, file: any, cb: any) {
    try {
      const contentLength = Number(req.headers['content-length']);
      if (
        typeof contentLength === 'number' &&
        contentLength > this.maxFileSize
      ) {
        throw new Error(`Max file size is ${this.maxFileSize} bytes.`);
      }
      const fileStream = await fileType.fileTypeStream(file.stream);
      const mime = fileStream.fileType?.mime ?? file.mimetype;
      if (!ALLOWED_MIME_TYPES.includes(mime)) {
        throw new BadRequestException('File must be *.csv or *.xlsx');
      }
      const replacementStream = new PassThrough();
      fileStream.pipe(replacementStream);
      const parser = createParserCsvOrXlsx(mime);
      const data = await parser.read(replacementStream);
      cb(null, {
        [this.destKey]:
          mime === 'text/csv' ? data : (data as Workbook).getWorksheet(),
      });
    } catch (error) {
      cb(error);
    }
  }
  _removeFile(req: Request, file: any, cb: any) {
    cb(null);
  }
}

Ce moteur de stockage personnalisé vérifie le type MIME du fichier et garantit qu'il s'agit d'un fichier CSV ou XLS/XLSX. Il traite ensuite le fichier entièrement en mémoire à l'aide des flux Node.js, donc aucun fichier temporaire n'est créé sur le serveur. Cette approche est à la fois efficace et sécurisée, notamment lorsqu'il s'agit de données sensibles.

Étape 4 : Création de l'usine d'analyseurs

L'usine d'analyseurs est chargée de déterminer l'analyseur approprié en fonction du type de fichier.

Créez un nouveau fichier pour notre analyseur :

import excel from 'exceljs';

export function createParserCsvOrXlsx(mime: string) {
  const workbook = new excel.Workbook();
  return [
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    'application/vnd.ms-excel',
  ].includes(mime)
    ? workbook.xlsx
    : workbook.csv;
}

Cette fonction d'usine vérifie le type MIME et renvoie l'analyseur approprié (soit xlsx, soit csv).

Étape 5 : Configuration de Multer dans le contrôleur NestJS

Ensuite, créons un contrôleur pour gérer les téléchargements de fichiers à l'aide de notre moteur de stockage personnalisé.

Générer un nouveau contrôleur :

nest g controller files

Dans files.controller.ts, configurez le téléchargement de fichiers à l'aide de Multer et du moteur de stockage personnalisé :

import {
  Controller,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { Worksheet } from 'exceljs';
import { CsvOrXlsxMulterEngine } from '../../shared/multer-engines/csv-xlsx/engine.js';
import { FilesService } from './files.service.js';

const MAX_FILE_SIZE_IN_MiB = 1000000000; // Only for test

@Controller('files')
export class FilesController {
  constructor(private readonly filesService: FilesService) {}
  @UseInterceptors(
    FileInterceptor('file', {
      storage: new CsvOrXlsxMulterEngine({
        maxFileSize: MAX_FILE_SIZE_IN_MiB,
        destKey: 'worksheet',
      }),
    }),
  )
  @Post()
  create(@UploadedFile() data: { worksheet: Worksheet }) {
    return this.filesService.format(data.worksheet);
  }
}

Ce contrôleur configure un point de terminaison pour gérer les téléchargements de fichiers. Le fichier téléchargé est traité par CsvOrXlsxMulterEngine et les données analysées sont renvoyées dans la réponse sans jamais être enregistrées sur le disque.

Étape 6 : Configuration du module

Enfin, nous devons mettre en place un module pour inclure notre contrôleur.

Générer un nouveau module :

nest g module files

Dans les fichiers.module.ts, importez le contrôleur :

import { Module } from '@nestjs/common';
import { FilesController } from './files.controller.js';
import { FilesService } from './files.service.js';

@Module({
  providers: [FilesService],
  controllers: [FilesController],
})
export class FilesModule {}

Assurez-vous d'importer ce module dans votre AppModule :

Étape 7 : Test du téléchargement de fichiers avec HTML

Pour tester la fonctionnalité de téléchargement de fichiers, nous pouvons créer une simple page HTML qui permet aux utilisateurs de télécharger des fichiers CSV ou XLS/XLSX. Cette page enverra le fichier à notre point de terminaison /api/files, où il sera analysé et traité en mémoire.

Voici le fichier HTML de base pour tester le téléchargement du fichier :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>File Upload</title>
</head>
<body>
    <h1>Upload a File (CSV or XLSX)</h1>
    <form action="/api/files" method="post" enctype="multipart/form-data">
        <label for="file">Choose file:</label>
        <input type="file" id="file" name="file" accept=".csv, .xlsx" required>
        <br><br>
        <button type="submit">Upload</button>
    </form>
</body>
</html>

Pour afficher la page HTML pour les téléchargements de fichiers, nous devons d'abord installer un module NestJS supplémentaire appelé @nestjs/serve-static. Vous pouvez le faire en exécutant la commande suivante :

npm install @nestjs/serve-static

Après l'installation, nous devons configurer ce module dans AppModule :

import { Module } from '@nestjs/common';
import { join } from 'path';
import { ServeStaticModule } from '@nestjs/serve-static';
import { FilesModule } from './modules/files/files.module.js';

@Module({
  imports: [
    FilesModule,
    ServeStaticModule.forRoot({
      rootPath: join(new URL('..', import.meta.url).pathname, 'public'),
      serveRoot: '/',
    }),
  ],
})
export class AppModule {}

Cette configuration nous permettra de servir des fichiers statiques à partir du répertoire public. Maintenant, nous pouvons ouvrir la page de téléchargement de fichiers en accédant à http://localhost:3000 dans votre navigateur.

Streamline File Uploads in NestJS: Efficient In-Memory Parsing for CSV & XLSX Without Disk Storage

Téléchargez votre fichier

파일을 업로드하려면 다음 단계를 따르세요.

  1. '파일 선택' 버튼을 클릭하여 파일을 선택하세요.
  2. 업로드 프로세스를 시작하려면 '업로드' 버튼을 클릭하세요.

파일이 성공적으로 업로드되면 파일이 업로드되고 포맷되었다는 확인 메시지가 표시됩니다.

Streamline File Uploads in NestJS: Efficient In-Memory Parsing for CSV & XLSX Without Disk Storage

참고: 업로드된 파일의 형식을 지정하는 코드는 포함하지 않았습니다. 이는 CSV 또는 XLS/XLSX 파일을 처리하기 위해 선택한 라이브러리에 따라 다르기 때문입니다. GitHub에서 전체 구현을 볼 수 있습니다.
인메모리 파일 처리의 장단점 비교
인메모리 파일 처리를 사용할지 디스크에 파일을 저장할지 결정할 때 장단점을 이해하는 것이 중요합니다.

인메모리 처리의 장점:

디스크에 임시 파일 없음:

  • 보안: 민감한 데이터가 서버 디스크에 남지 않아 데이터 유출 위험이 줄어듭니다.
  • 리소스 효율성: 서버는 임시 파일을 위한 디스크 공간을 할당할 필요가 없으며 이는 저장 공간이 제한된 환경에서 특히 유용할 수 있습니다.

더 빠른 처리:

  • 성능: 디스크에서 파일을 쓰고 읽는 오버헤드를 제거하므로 메모리의 파일을 구문 분석하는 속도가 더 빨라질 수 있습니다.
  • I/O 작업 감소: 디스크 I/O 작업이 적다는 것은 대기 시간이 짧고 강력하다는 것을 의미합니다. 파일 처리 처리량이 훨씬 더 높습니다.

단순화된 정리:

  • 정리 필요 없음: 파일이 디스크에 저장되지 않으므로 임시 파일을 관리하거나 정리할 필요가 없어 코드베이스가 단순화됩니다.

인메모리 처리의 단점:

메모리 사용량:

  • 높은 메모리 소비: 대용량 파일은 상당한 양의 메모리를 소비할 수 있으며, 서버에 리소스가 충분하지 않으면 메모리 부족 오류가 발생할 수 있습니다.
  • 확장성: 대용량 파일이나 여러 파일 업로드를 동시에 처리하려면 신중한 메모리 관리 및 확장 전략이 필요할 수 있습니다.

파일 크기 제한:

  • 메모리에 따른 제한: 처리할 수 있는 최대 파일 크기는 서버에서 사용 가능한 메모리에 따라 제한됩니다. 이는 의미 있는 일이 될 수 있습니다. 대용량 파일을 처리하는 애플리케이션의 단점.

오류 처리의 복잡성:

  • 오류 관리: 스트리밍 데이터의 오류를 관리하는 것은 디스크에서 파일을 처리하는 것보다 더 복잡할 수 있으며, 특히 부분 데이터를 복구하거나 분석해야 하는 경우에는 더욱 그렇습니다.

인메모리 처리를 사용하는 경우:

소형에서 중형 파일: 애플리케이션이 상대적으로 작은 파일을 처리하는 경우 인메모리 처리가 속도와 단순성을 제공할 수 있습니다.

보안에 민감한 애플리케이션: 디스크에 저장하면 안 되는 민감한 데이터를 처리할 때 메모리 내 처리를 통해 데이터 유출 위험을 줄일 수 있습니다.

고성능 시나리오: 높은 처리량과 최소 지연 시간이 필요한 애플리케이션은 인메모리 처리 오버헤드 감소의 이점을 누릴 수 있습니다.

디스크 기반 처리를 고려해야 하는 경우:

대용량 파일: 애플리케이션이 매우 큰 파일을 처리해야 하는 경우 메모리 부족을 방지하기 위해 디스크 기반 처리가 필요할 수 있습니다.

리소스가 제한된 환경: 서버 메모리가 제한된 경우 디스크에서 파일을 처리하면 메모리 고갈을 방지하고 리소스 관리를 향상할 수 있습니다.

지속적인 저장 요구: 감사, 백업 또는 향후 검색을 위해 업로드된 파일의 복사본을 보관해야 하는 경우 파일을 디스크에 저장해야 합니다.

외부 스토리지 서비스와의 통합: 대용량 파일의 경우 AWS S3, Google Cloud와 같은 외부 스토리지 서비스에 업로드하는 것이 좋습니다.

  • 스토리지 또는 Azure Blob Storage. 이러한 서비스를 사용하면 서버에서 스토리지를 오프로드할 수 있으며, 필요에 따라 클라우드에서 파일을 처리하거나 인메모리 처리를 위해 검색할 수 있습니다.

확장성: 클라우드 스토리지 솔루션은 대용량 파일을 처리하고 중복성을 제공하여 데이터가 안전하고 여러 지리적 위치에서 쉽게 액세스할 수 있도록 보장합니다.

비용 효율성: 클라우드 스토리지를 사용하면 로컬 서버 리소스의 필요성이 줄어들고 종량제 가격이 제공되므로 대용량 파일을 처리하는 데 더 비용 효율적일 수 있습니다.

결론

이 기사에서는 CSV 및 XLS/XLSX 파일을 처리하고, 메모리에서 구문 분석하고, 파일을 디스크에 저장하지 않고 구문 분석된 데이터를 반환하는 NestJS의 사용자 정의 파일 업로드 모듈을 만들었습니다. 이 접근 방식은 Node.js 스트림의 기능을 활용하여 서버에 임시 파일이 남지 않으므로 효율적이고 안전합니다.

또한 메모리 내 파일 처리와 디스크에 파일 저장의 장단점을 살펴보았습니다. 인메모리 처리는 속도, 보안 및 단순성을 제공하지만 이 접근 방식을 채택하기 전에 메모리 사용량과 잠재적인 파일 크기 제한을 고려하는 것이 중요합니다.

엔터프라이즈 애플리케이션을 구축하든 소규모 프로젝트를 구축하든 파일 업로드를 올바르게 처리하고 구문 분석하는 것이 중요합니다. 이 설정을 사용하면 불필요한 서버 저장이나 데이터 보안 문제에 대한 걱정 없이 NestJS에서 파일 업로드를 마스터할 수 있습니다.

아래 댓글 섹션에서 여러분의 생각과 개선 사항을 자유롭게 공유해 주세요!

이 기사가 마음에 들었거나 이러한 도구가 유용하다고 생각했다면 Dev.to에서 저를 팔로우하여 코딩 및 개발에 대한 더 많은 통찰력과 팁을 얻으세요. 여러분의 코딩 여정을 더욱 원활하게 만들어줄 유용한 콘텐츠를 정기적으로 공유합니다.

X(트위터)에서 저를 팔로우하세요. 여기서 프로그래밍과 기술에 대한 더 흥미로운 생각, 업데이트, 토론을 공유합니다! 놓치지 마세요 - 팔로우 버튼을 클릭하세요.

또한 LinkedIn에서 저를 팔로우하여 전문적인 통찰력, 최신 프로젝트 업데이트, 코딩, 기술 동향 등에 대한 토론을 받아보실 수도 있습니다. 개발 실력을 한 단계 끌어올릴 수 있는 귀중한 콘텐츠를 놓치지 마세요 - 함께해요!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn