字节轻服务(inspireCloud) + Express 框架接收formdata参数避坑指南

1,326 阅读3分钟

Express 框架接收formdata参数避坑指南

前言: 使用字节的轻服务serverless框架进行后端开发,遇到一个前端传图片的问题,而调用轻服务api存文件时需要 buffer 类型的数据,经过一番探索,终于解决 首先,express框架并不能解析formdata框架,所以通过postman测试接口时,后端打印的req.body是为 {}

这时就需要用到中间件了

  • 第一次我尝试了 body-parse ,发现此中间件不能解析 formdata

  • 第二次我尝试了express-formidable

image-20211201102750546.png 查阅了官方文档如上,使用postman发送请求后,返回结果如下

{
  myFile: File {
    _events: [Object: null prototype] {},
    _eventsCount: 0,
    _maxListeners: undefined,
    size: 67930,
    path: 'C:\\Users\\chihiro\\AppData\\Local\\Temp\\upload_bf95902d8666a9a7a3e7b4f775af21d7',
    name: 'v2-4e8fbb4310f65dde410a1579828e474c_qhd.jpg',
    type: 'image/jpeg',
    hash: null,
    lastModifiedDate: 2021-12-01T02:43:39.629Z,
    _writeStream: WriteStream {
      _writableState: [WritableState],
      _events: [Object: null prototype] {},
      _eventsCount: 0,
      _maxListeners: undefined,
      path: 'C:\\Users\\chihiro\\AppData\\Local\\Temp\\upload_bf95902d8666a9a7a3e7b4f775af21d7',
      fd: null,
      flags: 'w',
      mode: 438,
      start: undefined,
      autoClose: true,
      pos: undefined,
      bytesWritten: 67930,
      closed: true,
      [Symbol(kFs)]: [Object],
      [Symbol(kCapture)]: false,
      [Symbol(kIsPerformingIO)]: false
    },
    [Symbol(kCapture)]: false
  }
}

我的需求是是获取 文件的 key 值 和文件 buffer 但很显然这不能满足我的需求,它只返回了文件的临时路径,需要我自行去读取,并将其转换成buffer,这也不失为一种方法。

  • 以下是 文件 转 buffer

        let {myFile} = req.files
        var stream = fs.createReadStream(myFile.path);
        var responseData = [];//存储文件流
        if (stream) {//判断状态
            stream.on( 'data', function( chunk ) {
              responseData.push( chunk );
            });
            stream.on( 'end', function() {
               var finalData = Buffer.concat( responseData);
        uploadImageUtil.uploadImage(finalData,myFile.type)               
            });
        }       
  • uploadImage方法
exports.uploadImage = async (params, type) => {
    // params 就是文件 buffer
    // type 是文件类型
    // 通过 inspirecloud.file.upload 接口实现上传
    const { url } = await inspirecloud.file.upload(
        '1',    // 文件名
        params,// 文件内容
        {
            type,   // 文件类型,不传则会根据文件后缀名自动识别
        }
    );
    return url;
}
  • 第二个中间件用的是multer,具备转buffer和存文件两种功能,最终很顺畅的解决了我的问题

  • 首先介绍存文件的方式,原理和上述的一样

    • 首先在路由里进行配置
    const multer = require("multer");
    const path = require("path");
    // dest 文件存储路径
    const upload = multer({ dest:path.join(__dirname,"../../middleware") });
    /* 创建multer对象后,我们可以使用以下实例来接收上传文件:
    .single(fieldname) - 单个文件上传
    接收一个名为fieldname的上传文件,所上传的文件会被保存在req.file。
    .array(fieldname[, maxCount]) - 多个文件上传
    */
    router.post('/modifyUserInfo',auth,upload.single('myFile'),userCtrl.modifyUserInfo)
    // 至此文件已经可以实现存储,后续进行读取 并转换成buffer 在调用轻服务api即可
    
  • 再介绍可以直接获取buffer的方法

  • 引用multer模块后,我们会获取到一个顶级方法。该方法是一个工厂函数,可以使用这个方法创建Multer对象。它接受一个选项对象,最基本的选项是dest,它告诉 Multer 文件的存储位置。如果忽略该选项,文件会被保存在内存中,并且永远不会写入硬盘中。

  • 将dest去掉之后,发送请求,再打印req.file,我们可以获得如下结果

    {
      fieldname: 'myFile',
      originalname: 'v2-4e8fbb4310f65dde410a1579828e474c_qhd.jpg',
      encoding: '7bit',
      mimetype: 'image/jpeg',
      buffer: <Buffer ff d8 ff e0 00 10 4a 46 49 46 00 01 01 00 00 01 00 01 00 00 ff db 00 43 00 05 03 04 04 04 03 05 04 04 04 05 05 05 06 07 0c 08 04 04 04 03 05 04 04 04 05 05 05 06 07 0c 08 07 07 07 07 0f 0b 0b 09 ... 67880 more bytes>,
      size: 67930
    }
    

我们可以发现,文件直接就以buffer的形式给到了我们,相较于存文件再转buffer,这种直接保存在内存中的方法,更贴合轻服务的环境。

(参考文章:

[multer中间件]: (blog.csdn.net/anda9128/ar…

)