当前位置: 首页 > news >正文

【nest.js】创建一个上传api

下面详细介绍如何在 NestJS 中创建一个上传文件的功能。

Handling file uploads in NestJS is straightforward thanks to its integration with multer, a popular Node.js middleware for handling multipart/form-data.

Here’s a comprehensive example demonstrating how to set up an upload API in NestJS, covering single file, multiple files, and validation.


1. Project Setup (if you haven’t already)

# Create a new NestJS project
nest new nestjs-upload-example
cd nestjs-upload-example# Install multer and the NestJS platform-express package
npm install --save @nestjs/platform-express multer
# or
yarn add @nestjs/platform-express multer

2. Create the Uploads Directory

Create a folder where your uploaded files will be stored. For example, at the root of your project:

mkdir uploads

3. Implement the Upload Controller

This will contain your API endpoints for file uploads.

src/upload/upload.controller.ts (create a new folder src/upload)

import {Controller,Post,UploadedFile,UploadedFiles,UseInterceptors,ParseFilePipe,MaxFileSizeValidator,FileTypeValidator,HttpStatus,HttpException,
} from '@nestjs/common';
import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { extname, join } from 'path'; // Import 'join' from 'path'
import * as fs from 'fs'; // Import 'fs' for directory creation// Helper function to ensure the upload directory exists
const ensureDirExists = (dir: string) => {if (!fs.existsSync(dir)) {fs.mkdirSync(dir, { recursive: true });}
};const UPLOAD_DIR = './uploads'; // Define your upload directory@Controller('upload')
export class UploadController {constructor() {// Ensure the upload directory exists when the controller is initializedensureDirExists(UPLOAD_DIR);}// --- Single File Upload (without custom name, simple dest) ---@Post('single')@UseInterceptors(FileInterceptor('file', {// destination: UPLOAD_DIR, // Using 'dest' generates a random filename// For more control, use storage as shown belowstorage: diskStorage({destination: UPLOAD_DIR,filename: (req, file, cb) => {// Generating a unique filenameconst randomName = Array(32).fill(null).map(() => Math.round(Math.random() * 16).toString(16)).join('');cb(null, `${randomName}${extname(file.originalname)}`);},}),limits: {fileSize: 1024 * 1024 * 5, // 5 MB limit},fileFilter: (req, file, cb) => {if (!file.originalname.match(/\.(jpg|jpeg|png|gif|pdf)$/)) {return cb(new HttpException('Only image and PDF files are allowed!',HttpStatus.BAD_REQUEST,),false,);}cb(null, true);},}),)uploadSingleFile(@UploadedFile()file: Express.Multer.File, // 'Express.Multer.File' is the type for the file object) {if (!file) {throw new HttpException('File not provided', HttpStatus.BAD_REQUEST);}console.log('Uploaded file:', file);return {message: 'File uploaded successfully',filename: file.filename,path: file.path,};}// --- Single File Upload with ParseFilePipe (NestJS 9+ recommended for validation) ---@Post('single-validated')@UseInterceptors(FileInterceptor('file', {storage: diskStorage({destination: UPLOAD_DIR,filename: (req, file, cb) => {const randomName = Array(32).fill(null).map(() => Math.round(Math.random() * 16).toString(16)).join('');cb(null, `${randomName}${extname(file.originalname)}`);},}),// Note: Multer's fileFilter and limits can still be used for initial checks,// but ParseFilePipe offers more granular control and better error messages.}),)uploadValidatedFile(@UploadedFile(new ParseFilePipe({validators: [new MaxFileSizeValidator({ maxSize: 1024 * 1024 * 2 }), // 2 MBnew FileTypeValidator({ fileType: 'image/(jpeg|png|gif)' }), // Only images// Or for multiple types: new FileTypeValidator({ fileType: '(jpg|jpeg|png|gif|pdf)$' })],errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY, // Custom error code}),)file: Express.Multer.File,) {if (!file) {throw new HttpException('File not provided', HttpStatus.BAD_REQUEST);}console.log('Uploaded validated file:', file);return {message: 'Validated file uploaded successfully',filename: file.filename,path: file.path,};}// --- Multiple Files Upload ---@Post('multiple')@UseInterceptors(FilesInterceptor('files', 10, {// 'files' is the field name from the form, 10 is max countstorage: diskStorage({destination: UPLOAD_DIR,filename: (req, file, cb) => {const randomName = Array(32).fill(null).map(() => Math.round(Math.random() * 16).toString(16)).join('');cb(null, `${randomName}${extname(file.originalname)}`);},}),limits: {fileSize: 1024 * 1024 * 5, // 5 MB per file},fileFilter: (req, file, cb) => {if (!file.originalname.match(/\.(jpg|jpeg|png|gif|pdf)$/)) {return cb(new HttpException('Only image and PDF files are allowed for multiple uploads!',HttpStatus.BAD_REQUEST,),false,);}cb(null, true);},}),)uploadMultipleFiles(@UploadedFiles()files: Array<Express.Multer.File>,) {if (!files || files.length === 0) {throw new HttpException('No files provided', HttpStatus.BAD_REQUEST);}console.log('Uploaded files:', files);return {message: 'Files uploaded successfully',count: files.length,filenames: files.map((f) => f.filename),paths: files.map((f) => f.path),};}
}

4. Register the Controller in your Module

You need to add UploadController to the controllers array in your app.module.ts or a feature module.

src/app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UploadController } from './upload/upload.controller'; // Import your new controller@Module({imports: [],controllers: [AppController, UploadController], // Add UploadController hereproviders: [AppService],
})
export class AppModule {}

5. Running the Application

npm run start:dev
# or
yarn start:dev

Your server will typically run on http://localhost:3000.


6. Testing the Endpoints

You can use curl, Postman, Insomnia, or a simple HTML form to test these endpoints.

A. Using curl (Recommended for quick tests)

Single File Upload:

curl -X POST \http://localhost:3000/upload/single \-H 'Content-Type: multipart/form-data' \-F 'file=@/path/to/your/image.jpg' # Replace with actual path to an image or PDF

Single File Upload with Validation:

curl -X POST \http://localhost:3000/upload/single-validated \-H 'Content-Type: multipart/form-data' \-F 'file=@/path/to/your/image.png' # Must be image and <= 2MB

Multiple Files Upload:

curl -X POST \http://localhost:3000/upload/multiple \-H 'Content-Type: multipart/form-data' \-F 'files=@/path/to/your/image1.jpg' \-F 'files=@/path/to/your/document.pdf' \-F 'files=@/path/to/your/image2.png'

(Note: Each -F 'files=@...' needs to use the same field name files)

B. Using a simple HTML Form

Create an index.html file in your project root for testing:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>NestJS Upload Test</title><style>body {font-family: sans-serif;padding: 20px;}form {margin-bottom: 30px;padding: 20px;border: 1px solid #ccc;border-radius: 5px;}input[type='file'] {display: block;margin-bottom: 10px;}button {padding: 8px 15px;background-color: #007bff;color: white;border: none;border-radius: 4px;cursor: pointer;}button:hover {background-color: #0056b3;}h2 {margin-top: 0;}</style></head><body><h1>NestJS File Upload Examples</h1><formaction="http://localhost:3000/upload/single"method="post"enctype="multipart/form-data"><h2>Single File Upload (Basic)</h2><input type="file" name="file" /><button type="submit">Upload Single File</button></form><formaction="http://localhost:3000/upload/single-validated"method="post"enctype="multipart/form-data"><h2>Single File Upload (Validated, Max 2MB, Image Only)</h2><input type="file" name="file" /><button type="submit">Upload Validated File</button></form><formaction="http://localhost:3000/upload/multiple"method="post"enctype="multipart/form-data"><h2>Multiple Files Upload (Max 10 files, up to 5MB each, Image/PDF)</h2><input type="file" name="files" multiple /><button type="submit">Upload Multiple Files</button></form></body>
</html>

Open this index.html file in your browser to test the uploads.


Key Concepts and Notes:

  1. @nestjs/platform-express: This package provides the FileInterceptor and FilesInterceptor decorators, which are wrappers around multer.
  2. multer: The underlying library for handling multipart/form-data.
    • FileInterceptor(fieldName, options): For a single file. fieldName is the name of the input field in your form (e.g., <input type="file" name="file">). options are Multer options.
    • FilesInterceptor(fieldName, maxCount, options): For multiple files. maxCount is the maximum number of files allowed.
  3. @UploadedFile() / @UploadedFiles(): Decorators to inject the uploaded file(s) into your route handler. The type is Express.Multer.File for a single file, and Array<Express.Multer.File> for multiple files.
  4. diskStorage: This multer option gives you fine-grained control over where files are stored and how they are named.
    • destination: A function or string that determines the folder where the files should be stored.
    • filename: A function that determines the name of the file inside the destination folder.
  5. limits: Multer options to restrict file size, number of files, etc.
  6. fileFilter: A function that lets you control which files should be uploaded and which should be skipped. It’s useful for checking file types based on extensions or MIME types. If you return false or throw an HttpException, the file will be rejected.
  7. ParseFilePipe (NestJS 9+): This is the recommended NestJS-native way for more robust and descriptive file validation. It works with @UploadedFile() and @UploadedFiles() (though the latter requires an additional pipe for array validation). It provides:
    • MaxFileSizeValidator: To check the file size.
    • FileTypeValidator: To check the file’s MIME type.
    • Better error messages and custom errorHttpStatusCode.
  8. Error Handling: Multer errors (e.g., file size limits, invalid file type from fileFilter) are automatically caught by NestJS’s exception filters and converted into appropriate HTTP responses. ParseFilePipe also throws BadRequestException by default, which NestJS handles.
  9. Security: Always validate file types, sizes, and potentially scan for malicious content. Storing user-uploaded files directly in your web server’s public directory without sanitization can be a security risk. It’s often better to serve them through a dedicated route or store them in a CDN/cloud storage.
  10. Directory Creation: The ensureDirExists helper makes sure your uploads folder exists before Multer tries to save files there.

This example provides a solid foundation for building file upload functionality in your NestJS applications.


文章转载自:

http://EfZqqviY.prprj.cn
http://krDNKiyG.prprj.cn
http://LYdHdg4Q.prprj.cn
http://Pcnebzhf.prprj.cn
http://aWR3oiXE.prprj.cn
http://32RIuAiV.prprj.cn
http://JZE4IYjr.prprj.cn
http://dknxupWa.prprj.cn
http://KaCnN4se.prprj.cn
http://eBqfvyIe.prprj.cn
http://jSfGR0Lj.prprj.cn
http://HfMFhdnW.prprj.cn
http://9MmAXsOo.prprj.cn
http://hJE0peUF.prprj.cn
http://9EKYgGjY.prprj.cn
http://orAqbSuf.prprj.cn
http://XRnPxfWb.prprj.cn
http://FeFilD4q.prprj.cn
http://KACjXxfJ.prprj.cn
http://RrIaYznU.prprj.cn
http://Mw7O1qQR.prprj.cn
http://XhsDLDYU.prprj.cn
http://10j7pCGk.prprj.cn
http://9NvbnoEI.prprj.cn
http://wOKGi9CV.prprj.cn
http://U7cplsVN.prprj.cn
http://b0qWZQq9.prprj.cn
http://3DzhXt9E.prprj.cn
http://CB2uPWXE.prprj.cn
http://3HJJHiOs.prprj.cn
http://www.dtcms.com/a/373973.html

相关文章:

  • C语言内存精讲系列(八):深化详述 int 3
  • 蓓韵安禧DHA为孕期安全营养补充提供科学支持,呵护母婴健康
  • 什么是状态(State)以及如何在React中管理状态?
  • Anaconda与Jupyter 安装和使用
  • 房屋安全鉴定需要什么条件
  • 全国产压力传感器选型指南/选型手册
  • 时间比较算法(SMART PLC梯形图示例)
  • 查找---二分查找
  • 求解二次方程
  • ArcGISPro应用指南:使用ArcGIS Pro制作弧线OD图
  • ZYNQ EMMC
  • uni-app头像叠加显示
  • 链改 2.0 六方共识深圳发布 ——“可信资产 IPO + 数链金融 RWA” 双轮驱动
  • ARM -- 汇编语言
  • HTML和CSS学习
  • 深度解析:IService 与 ServiceImpl 的区别
  • STM32 - Embedded IDE - GCC - rt_thread_nano的终端msh>不工作的排查与解决
  • 房屋安全鉴定报告有效期多久
  • Redux的使用
  • 深入理解 Redis:特性、应用场景与实践指南
  • Linux应用(3)——进程控制
  • (Arxiv-2025)MOSAIC:通过对应感知的对齐与解缠实现多主体个性化生成
  • 制造业多数据库整合实战:用 QuickAPI 快速生成 RESTful API 接入 BI 平台
  • outOfMemory内存溢出
  • Pandas数据结构(DataFrame,字典赋值)
  • 谈谈对this的理解
  • CVE-2025-2502 / CNVD-2025-16450 联想电脑管家权限提升漏洞
  • 用 Trae 玩转 Bright Data MCP 集成
  • CiaoTool 批量钱包 多对多转账实战:跨链应用全解析
  • Decision Tree Model|决策树模型