接上一篇大文件上传1(前端),这篇主要是后端实现大文件上传的功能,使用的是node + nestjs
创建file-upload相关文件
nest g module file-upload
nest g controller file-upload
nest g service file-upload
安装依赖
pnpm i @nestjs/platform-express express multer
file-upload.controller.ts
import { Controller, Post, UploadedFile, UseInterceptors, Body, Res } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { FileUploadService } from './file-upload.service';
import {ApiTags} from '@nestjs/swagger'
import { Response } from 'express';
@ApiTags('上传文件')
@Controller('fileUpload')
export class FileUploadController {
constructor(private readonly fileUploadService: FileUploadService){}
@Post()
@UseInterceptors(FileInterceptor('chunk'))
async uploadFile(@UploadedFile() file: Express.Multer.File, @Body() body: any, @Res() res: Response){
const {hash} = body
try {
await this.fileUploadService.saveChunk(file, hash);
res.status(200).send('Chunk uploaded successfully');
} catch (error) {
res.status(500).send('Error uploading chunk');
}
}
@Post('merge')
async mergeFile(@Body() body:any, @Res() res: Response){
const {hash, fileName} = body;
try {
await this.fileUploadService.mergeChunks(hash, fileName)
res.status(200).send('merge successfully');
} catch (error) {
res.status(500).send('Error merge chunk');
}
}
}
file-upload.module.ts
import { Module } from '@nestjs/common';
import { MulterModule } from '@nestjs/platform-express';
import { FileUploadController } from './file-upload.controller';
import { FileUploadService } from './file-upload.service';
import { diskStorage } from 'multer'
import { extname } from 'path';
@Module({
imports: [
MulterModule.register({
storage: diskStorage({
destination:'./uploads',
filename: (req, file, cb)=> {
const uniqueSuffix = Date.now() + '-'+Math.round(Math.random()*1E9)
cb(null, `${uniqueSuffix}${extname(file.originalname)}`)
}
})
})
],
controllers: [FileUploadController],
providers: [FileUploadService]
})
export class FileUploadModule {}
file-upload.service.ts
import { Injectable } from '@nestjs/common';
import {promises as fs} from 'fs'
import {join} from 'path'
@Injectable()
export class FileUploadService {
//将上传的文件放在 uploads
private readonly uploadDir = "./uploads";
async saveChunk (file: Express.Multer.File, hash: string) {
const chunkDir = join(this.uploadDir, hash.split('-')[0])
await fs.mkdir(chunkDir, {recursive: true})
await fs.rename(file.path, join(chunkDir, hash))
}
async mergeChunks (hash: string, fileName: string) {
const chunkDir = join(this.uploadDir, hash)
const chunks = await fs.readdir(chunkDir)
chunks.sort((a,b) => parseInt(a.split('-')[1])-parseInt(b.split('-')[1]))
const filePath = join(this.uploadDir,fileName)
for (const chunk of chunks) {
const chunkPath = join(chunkDir, chunk)
const data = await fs.readFile(chunkPath)
await fs.appendFile(filePath, data)
await fs.unlink(chunkPath)
}
await fs.rmdir(chunkDir)
}
}
启动 nest 就可以了