SunXinFei / sunxinfei.github.io

前后端技术相关笔记,已迁移到 Issues 中
https://github.com/SunXinFei/sunxinfei.github.io/issues
32 stars 3 forks source link

Node 文件上传 #16

Open SunXinFei opened 5 years ago

SunXinFei commented 5 years ago

nodejs 实现文件上传

这里的nodejs后台依赖为koa,koa不能直接从请求中获取file,我们需要引入一个插件koa-body,koa-body有两种嵌入方式一种是在app.js中使用use,第二种是在路由层面,针对于某个路由嵌入,例如:

router.post('/upload/:interface', koaBody({
  multipart: true,
  encoding: 'gzip',
  onError: (error, ctx) => {
    ctx.body = {
      code: 400,
      error
    };
  },
})
  , InterfaceController.upload)

这里要说明一下,koabody中有formidable属性,通过对该属性配置,其实就可以实现文件的上传以及下载,这里为了让路由层面的代码整洁,所以没有直接在koabody层面上做属性配置,还有一点要值得注意koabody中有formidable属性并不全和node-formidable的api相比,很多属性并不能使用,例如progress、end、error等,这些都没有。 另外一点要注意的是koabody的版本,版本不同会导致按照网上搜到的教程从ctx中获取file的属性层级会不同,我使用的是koabody v4.1.0。

static async upload(ctx) {
   //获取请求中的接口名称
    let interfaceName = ctx.params.interface;
    //获取文件
    const file = ctx.request.files['file'];
   //创建文件reader
    const reader = fs.createReadStream(file.path);
    // 最终要保存到的文件夹目录,这里我放在server的上一层目录,创建api3/public/upload/接口名称的文件夹
    const dir = path.join(path.resolve(__dirname, '../../'), `api3/public/upload/${interfaceName}`);
    // 检查文件夹是否存在如果不存在则递归新建文件夹
    if (fs.existsSync(dir) === false) {
      utils.mkdirs(dir);
    }
    // 重新覆盖 file.path 属性
    file.path = `${dir}/${file.name}`;
   //创建文件流并写入
    const stream = fs.createWriteStream(file.path);
    reader.pipe(stream);
   //返回文件的路径
    ctx.body = {
      code: '1000',
      msg: "上传成功",
      data: {
        path: file.path
      }
    }
  }

这里用到了一个递归创建文件夹的方法

/**
 * 递归创建文件夹
 * @param {String} dirpath 创建的文件夹路径
*/
utils.mkdirs = function mkdirs(dirpath){
  if (!fs.existsSync(path.dirname(dirpath))) {
    mkdirs(path.dirname(dirpath));
  }
  fs.mkdirSync(dirpath);
}

到这里就在koa中实现文件的上传功能,当文件上传成功之后,返回文件的路径