Dream-Life
  • 首页
  • 技术
  • 小日记
  • 百宝盒
  • 小站
avatar
Nest(Fastify底层)使用fastify/multipart上传方式
avatarDream
2023-10-28
3475次阅读
3个评论

写这个是记录一下在Fastify底层写上传的方式,因为默认Nest的底层是Express

Nest文档中对Express和Fastify的解释以及如何切换Fastify

在Nest文档中也有提到上传,不过默认是适用于Express
express-multer模块上传方式

如果是用Fastify最简单方式就是使用fastify官方提供的包fastify/multipart

fastify-multipart(github)地址
更详细的说明可以看Github

一、安装

安装还是老三样 npm Yarn pnpm
我是用的pnpm

tem 复制代码
pnpm i @fastify/multipart

二、注册插件

注册在入口文件main.ts里面
通过fastify注册方法register

typescript 复制代码
import multipart from '@fastify/multipart';

  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter(),
    { cors: true },
  );

  // 如下注册
  await app.register(multipart, {
    // 注册参数,Infinity就是无限大,
    // 不写fileSize和files的话 默认是10MB和最大上传一个文件
    limits: {
    fileSize: Infinity, // For multipart forms, the max file size in byt    
    files: Infinity,    // Max number of file fields
    fieldNameSize: 100, // Max field name size in bytes
    fieldSize: 100,     // Max field value size in bytes
    fields: 10,         // Max number of non-file fields 
    headerPairs: 2000,  // Max number of header key=>value pairs
    parts: 1000         // For multipart forms, the max number of parts 
    },
  });

注册完以后就可以去server层使用了,具体更多的使用方法可以参考fastify-multipart

三、使用

先在controller层写上传方法

typescript 复制代码
// 引用类型
import type { FastifyRequest, FastifyReply } from 'fastify';
import { Request, Response } from '@nestjs/common';

  @Post('uploadFile')
  async uploadFile(
    @Request() request: FastifyRequest,
    @Response() response: FastifyReply,
  ) {
    return await this.loadFileService.uploadFile(request, response);
  }
  

实现完Controller当然开始写Service层了

typescript 复制代码
import * as fs from 'fs';

  async uploadFile(request: FastifyRequest, response: FastifyReply) {
      // 这个file就是上传的流文件,request里面还有个files是文件流数组
      const file = await request.file();

    
      // 拿到文件流就随便玩啦!
      // 下面就是我自己对file做的操作,也可以上传到Oss,或者其他地方。
      const config = await this.yamlConfigService.getUploadConfig();
      if (config) {
        // 调用node的fs模块,创建写入流,这里的地址是我拼接写入的地方,
        const writeStream = fs.createWriteStream(
          `${config.uploadPosition}${file.filename}`,
        );
        //通过pipe写入,
        file.file.pipe(writeStream);
        // 监听写入流的错误
        writeStream.once('error', (e) => {
          console.error(e);
          // 出现错误就接口返回500给前台。
          response
            .code(HttpStatus.SERVICE_UNAVAILABLE)
            .send(
              responseError(
                '上传失败,请稍后尝试!',
                HttpStatus.SERVICE_UNAVAILABLE,
              ),
            );
        });
        // 监听写入流完成事件
        writeStream.once('finish', () => {
          const result = {
            url: `${config.endpoint}/${file.filename}`,
            name: file.filename,
          };
          // 通过response 返回给接口数据。
          response.code(HttpStatus.OK).send(responseSuccess(result));
        });
        
        // 当然也要执行end事件,去做后续清理,手动释放内存啦!
        writeStream.once('end', async () => {
          writeStream.removeAllListeners();
          await request.cleanRequestFiles();
          writeStream.close();
        });
        writeStream.end();
      }
    } 
  }

四、注意问题

当要取除文件外的其他字段值需要特别注意

注意:按顺序(流)使用多部分。因此,表单字段的顺序对于如何data.fields向您显示字段非常重要。我们建议您将值字段放在任何文件字段之前。这将确保您的字段在开始使用任何文件之前可访问。如果您无法控制放置字段的顺序,请务必在使用流之后读取,否则它将仅包含当时解析的字段。

TypeScript 复制代码
    const files = request.files();
    const fileParams = await files.next();
    const { ... } = fileParams.value.fields //这里面就是要取的其他字段

    //当然你如果直接要取文件跟第三步一样,但是取不到其他字段
    const file = request.file();
    

五、总结

在使用fastify/multipart包确实是一个不错的上传选择方案。
极大简化了fastify底层的使用成本。

文章最后更新于 2024-12-22 23:36
评论一下吧!
F
FiZz2024-11-09
😀
User Image
avatar
Dream2024-11-09
🙃
User Image
F
FiZz2024-11-09
回复 @Dream
66666
avatarBgc
avatar
Dream-Life
treasure every day
文章6
类型9
标签10
Catalog
世上只有一种英雄主义,那就是看清生活真相后依然热爱生活。
湘ICP备19022890号-1
Copyright © 2023 DreamLife