引言
在当今的Web应用中,高效的文件上传至关重要。本文将介绍如何从前端页面调用NestJS提供的文件上传接口,并通过该接口将文件流直接上传至第三方服务,以此提升上传效率和用户体验。通过这一流程,我们将展示如何利用NestJS与外部存储系统无缝集成,实现流畅的文件处理机制。
具体操作流程
以下代码所有涉及的依赖默认您的项目都已经安装完毕。
1.前端页面
// upload.vue
<NUpload
ref="uploadRef"
:custom-request="customRequest"
:show-file-list="false"
>
<NBoutton>文件上传</NButton>
</NUpload>
<script setup lang="ts">
import { NButton, type UploadCustomRequestOptions } from 'naive-ui';
import { uploadFile } from './UploadApi';
import dayjs from 'dayjs';
const uploadRef = ref(null);
async function customRequest({ file }: UploadCustomRequestOptions) {
// 修改文件名
const modifiedFileName = `${dayjs().valueOf()}${file.name.substring(file.name.lastIndexOf('.'))}`;
const modifiedFile = new File([file.file as File], modifiedFileName);
const formData = new FormData();
formData.append('file', modifiedFile);
formData.append('prefix', 'avatar'); // 传多余参数
// 调用上传接口
const data = await uploadFile(formData);
// ... 其他逻辑处理
}
</script>
// uploadApi.ts
import { request } from '@/utils/http/axiosWrapper';
/**
* 文件上传
*/
export async function uploadFile(
formData: FormData
): Promise<any> {
const response = await request.post('/bimface/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
return response.data.data;
}
2.NestJs接口服务
让我们详细说明如何在 NestJS 服务器中将 file.buffer
写入文件中,然后使用 createReadStream
读取成文件流。
步骤概述
-
接收上传的文件并保存到缓冲区
(file.buffer)
。 -
将缓冲区数据写入临时文件。
-
使用
createReadStream
读取文件流。 -
发送文件流到远程服务器或其他处理逻辑。
示例代码
- 创建文件上传控制器
在 src/app
目录下创建 upload.controller.ts
:
// src/app/upload.controller.ts
import {
Controller,
Post,
UploadedFile,
UseInterceptors,
Body,
} from '@nestjs/common';
import { UploadService } from './upload.service';
import { ApiBody, ApiConsumes, ApiOperation } from '@nestjs/swagger';
import { FileInterceptor } from '@nestjs/platform-express';
import {
HubMeta,
FolderInfo,
ProjectInfo,
TranslateFileStatus,
TranslateFile,
} from './bfwrapper.dto';
@Controller('bimface')
export class UploadController {
constructor(private readonly uploadService: UploadService) {}
@Post('upload')
@ApiOperation({ summary: '上传文件' })
@UseInterceptors(FileInterceptor('file'))
@ApiBody({
schema: {
type: 'object',
properties: {
file: {
type: 'string',
format: 'binary',
},
},
required: ['file'],
},
})
@ApiConsumes('multipart/form-data')
uploadFile(@UploadedFile() file: Express.Multer.File) {
return this.uploadService.upload(file);
}
}
- 创建流式文件处理服务
在 src/services
目录下创建 upload.service.ts
:
// src/services/upload.service.ts
import { createReadStream, createWriteStream, unlinkSync } from 'fs';
import { pipeline } from 'stream';
import { promisify } from 'util';
import axios from 'axios';
import { tmpdir } from 'os';
const pipelineAsync = promisify(pipeline);
export class UploadService {
async upload(file: Express.Multer.File) {
// 第三方普通文件流上传接口
const requestUrl: string = https://api.bimface.com/bdfs/data/v1/projects/100000002/fileItems;
// 处理文件名称中的中文乱码
file.originalname = Buffer.from(file.originalname, 'latin1').toString('utf8');
// 1.创建临时文件路径
const tempFilePath = `${tmpdir()}/${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
console.log('tempFilePath', tempFilePath);
// 2.将缓冲区数据写入临时文件。
const writeStream = createWriteStream(tempFilePath);
await new Promise((resolve, reject) => {
writeStream.on('finish', ()=> {
resolve(tempFilePath);
});
writeStream.on('error', () => {
reject(error);
});
writeStream.write(file.buffer);
writeStream.end();
});
// 3.使用 createReadStream 读取文件流。
const tempFileStream = createReadStream(tempFilePath);
// 4.发送文件流到第三方服务器或其他处理逻辑。
try {
const { data } = await firstValueFrom(
this.httpService.post(requestUrl, tempFileStream, {
params: {
name: file.originalname,
parentId: this.rootFolderId,
length: file.size,
},
headers: {
Authorization: this.token,
'Content-Length': file.size,
'Content-Type': 'application/octet-stream',
},
}),
);
return data.data;
} catch (error: any) {
console.log(error);
} finally {
// 5.删除临时文件
unlinkSync(tempFilePath);
}
}
}
解释
-
接收上传的文件并保存到缓冲区
(file.buffer)
在
uploadFile
方法中,通过@UploadedFile()
接收上传的文件,并获取其buffer
属性。 -
将缓冲区数据写入临时文件
在
handleBuffer
方法中,使用createWriteStream
创建一个写入流,并将缓冲区数据写入临时文件。 -
使用
createReadStream
读取文件流使用
createReadStream
创建一个读取流,从临时文件中读取数据。 -
文件流到远程服务器或其他处理逻辑
使用
Axios
发送文件流到远程服务器,并处理响应。
总结
通过上述步骤,你可以将上传的文件保存到缓冲区,然后写入临时文件,并使用 createReadStream
读取文件流进行进一步处理。这种方式可以有效地处理文件上传,并确保文件数据的完整性和安全性。
喜欢的话帮忙点个赞 + 关注吧,将持续更新 Nestjs
相关的文章,还可以关注我的公众号 梁三石FE
,感谢您的关注~