node.js express框架实现文件上传与下载功能实例详解

本文实例讲述了node.js express框架实现文件上传与下载功能。分享给大家供大家参考,具体如下:

背景

昨天吉视传媒的客户对IPS信息发布系统又提了一个新需求,就是发布端发送消息时需要支持附件的上传,而接收端可以对发布端上传的附件进行下载;接收端回复消息时也需要支持上传附件,发布端可以对所有接收端上传的附件进行打包下载。

功能实现

  • 前台部分

前台使用webUploader插件即可,这是百度开发的一款文件上传组件,具体使用查看它的API即可。这个项目之前开发的时候前台使用了angular.js。

  $scope.fileName = "";
  //创建上传附件的对象
  var $list = $("#thelist");
  var uploader = WebUploader.create({
    // 选完文件后,是否自动上传。
    auto: false,
    // swf文件路径
    swf: '../../../lib/webUploader/Uploader.swf',
    // 文件接收服务端。
    server: '/publishUploadFile',
    // 内部根据当前运行是创建,可能是input元素,也可能是flash.
    pick : {
      id : '#filePicker',
      //只能选择一个文件上传
      multiple: false
    },
    // pick :'#filePicker',
    method: 'POST',
  });
  uploader.on('fileQueued', function (file) {
    $scope.fileName = file.name;
    $list.html("");
    $list.html(file.name);
  });

当用户选择文件的时候我创建了文件上传的对象,而在用户真正发送消息的时候我添加了相应的参数并将附件真正的上传上去,符合我这个项目的业务逻辑。

if($scope.fileName){
  //添加参数
  uploader.options.formData.fileId = fileId;
  uploader.options.formData.fileName = $scope.fileName;
  uploader.upload();
}
  • 后台部分

路由就不详细说明了,主要注意的是下载的接口我都是使用的get请求,这样前台在请求的时候直接新打开一个窗口拼接了相应的参数就能下载文件了。下面贴一下action层的代码:

//发布端上传附件
exports.publishUploadFile = function (req, res) {
  messageMng.publishUploadFile(req, function (err, datas) {
    res.json(datas);
  });
};
//下载发布端上传的附件
exports.exportPublishFile = function (req, res) {
  messageMng.exportPublishFile(req, function (err, datas) {
    if (err) {
      res.set({
        "Content-Disposition": "attachment;filename=" + encodeURI("error.txt")
      });
      res.write(err.message);
      res.end();
    } else {
      res.download(datas.path, encodeURI(datas.name));
    }
  });
};
//接收端上传附件
exports.uploadFile = function (req, res) {
  messageMng.uploadFile(req, function (err, datas) {
    res.json(datas);
  });
};
//发布端导出附件
exports.exportFile = function (req, res) {
  messageMng.exportFile(req, function (err, datas) {
    if (err) {
      res.set({
        "Content-Disposition": "attachment;filename=" + encodeURI("error.txt")
      });
      res.write(err.message);
      res.end();
    } else {
      //第一种方式 下载完的zip解压报错
      // res.download(datas.path, datas.name + ".zip");
      //第二种方式
      // var path="D:/maven介绍.ppt";
      var f = fs.createReadStream(datas.path);
      res.writeHead(200, {
        'Content-Type': 'application/force-download',
        'Content-Disposition': 'attachment; filename='+ encodeURI(datas.name) + '.zip'
      });
      f.pipe(res);
    }
  });
};

这里着重说一下下载zip时使用download下载完的压缩包解压会报错,使用第二种方法完美解决。

然后是service层的代码:

/**
 * 发布端上传附件
 * @param req
 * @param fn
 */
MessageManager.prototype.publishUploadFile = function (req, fn) {
  try {
    //消息ID
    var fileId = req.body.fileId;
    var file = req.file;
    //文件上传的目录
    var uploadFolder = path.join(__dirname, '../../upload/publishUploadFile/' + fileId);
    //判断文件夹是否存在 不存在则创建
    toolUtil.mkdirSync(uploadFolder);
    //将上传的文件从临时目录拷贝到指定的目录下
    var fileReadStream = fs.createReadStream(file.path);
    var fileWriteStream = fs.createWriteStream(uploadFolder + "/" + file.originalname);
    fileReadStream.pipe(fileWriteStream);
    fileWriteStream.on('close', function () {
      // 删除临时目录下面的文件
      toolUtil.emptyDir(file.destination);
    });
    fn(null, {"data": "", "message": "上传成功", "error_code": 200});
  } catch (e) {
    fn(e, {"data": "", "message": "上传失败", "error_code": e.message});
  }
};
/**
 * 下载发布端上传的附件
 * @param req
 * @param fn
 */
MessageManager.prototype.exportPublishFile = function (req, fn) {
  try {
    //附件ID
    var id = req.query.id;
    //附件名称或标题
    var name = req.query.name;
    if (id && name) {
      //名称过长的话,截取前25个字符
      if (name.length > 25) {
        name = name.substr(0, 24);
      }
      //将要压缩得文件夹路径
      var filePath = path.join(__dirname, '../../upload/publishUploadFile/' + id + '/' + name);
      if (!fs.existsSync(filePath)) {
        fn(new Error("没有附件!"), null);
      } else {
        fn(null, {"name": name, "path": filePath});
      }
    } else {
      fn(new Error("id或name不能为空"), null);
    }
  } catch (e) {
    fn(new Error(e.message), null);
  }
};
/**
 * 接收端上传附件
 * @param req
 * @param fn
 */
MessageManager.prototype.uploadFile = function (req, fn) {
  try {
    //消息ID
    var msgId = req.body.msgId;
    //消息发送的时间
    var msgSendTime = req.body.msgSendTime.slice(0, 10);
    //消息的标题
    var title = req.body.title;
    var replyId = req.body.replyId;
    var replyName = req.body.replyName;
    var file = req.file;
    //文件上传的目录
    var uploadFolder = path.join(__dirname, '../../upload/messages/' + msgId + '/' + replyName);
    //判断文件夹是否存在 不存在则创建
    toolUtil.mkdirSync(uploadFolder);
    //组装文件的名称 原名称+消息发送时间
    var index = file.originalname.lastIndexOf(".");
    var fileName = file.originalname.substr(0, index) + '-' + msgSendTime + "";
    var suffix = file.originalname.substr(index, file.originalname.length - 1);
    //将上传的文件从临时目录拷贝到指定的目录下
    var fileReadStream = fs.createReadStream(file.path);
    var fileWriteStream = fs.createWriteStream(uploadFolder + "/" + fileName + "." + suffix);
    fileReadStream.pipe(fileWriteStream);
    fileWriteStream.on('close', function () {
      //删除临时目录下面的文件
      toolUtil.emptyDir(file.destination);
    });
    fn(null, {"data": "", "message": "上传成功", "error_code": 200});
  } catch (e) {
    fn(e, {"data": "", "message": "上传失败", "error_code": e.message});
  }
};
/**
 * 导出消息的附件文件
 * @param req
 * @param fn
 */
MessageManager.prototype.exportFile = function (req, fn) {
  try {
    //消息ID
    var id = req.query.id;
    //消息名称或标题
    var name = req.query.name;
    if (id && name) {
      //名称过长的话,截取前25个字符
      if (name.length > 25) {
        name = name.substr(0, 24);
      }
      //将要压缩得文件夹路径
      var messagePath = path.join(__dirname, '../../upload/messages/' + id);
      if (!fs.existsSync(messagePath)) {
        fn(new Error("没有附件!"), null);
      } else {
        //生成得临时zip文件目录
        var zipPath = path.join(__dirname, '../../upload/temp.zip');
        var archive = archiver('zip', {
          // Sets the compression level.
          zlib: {level: 9}
        });
        //创建临时zip文件
        var output = fs.createWriteStream(zipPath);
        archive.pipe(output);
        //设置需要压缩得文件夹目录 以及替换得名称
        archive.directory(messagePath, name);
        archive.finalize();
        archive.on('end', function (err) {
          fn(null, {"name": name, "path": zipPath});
        });
        archive.on('error', function (err) {
          fn(new Error("压缩文件异常"), null);
        });
      }
    } else {
      fn(new Error("id或name不能为空"), null);
    }
  } catch (e) {
    fn(new Error(e.message), null);
  }
};

最后是提出的公共方法toolUtil的代码,这个单独做为一个js文件维护。

const path = require('path');
const fs = require('fs');
/**
 * 创建目录
 * @param dirpath
 */
exports.mkdirSync = function (dirpath){
  if (!fs.existsSync(dirpath)) {
    var pathtmp;
    dirpath.split(path.sep).forEach(function(dirname) {
      if (pathtmp) {
        pathtmp = path.join(pathtmp, dirname);
      }
      else {
        pathtmp = dirname;
      }
      if (!fs.existsSync(pathtmp)) {
        fs.mkdirSync(pathtmp);
      }
    });
  }
};
//删除所有的文件(将所有文件夹置空)
exports.emptyDir = function(dirpath){
  var self = this;
  //读取该文件夹
  var files = fs.readdirSync(dirpath);
  files.forEach(function(file){
    var filePath = dirpath + '/' + file;
    var stats = fs.statSync(filePath);
    if(stats.isDirectory()){
      self.emptyDir(filePath);
    }else{
      fs.unlinkSync(filePath);
    }
  });
};

希望本文所述对大家node.js程序设计有所帮助。

(0)

相关推荐

  • 浅析Node.js实现HTTP文件下载

    前言 HTTP实现文件下载时,只要在服务器设置好相关响应头,并使用二进制传输文件数据即可,而客户端(浏览器)会根据响应头接收文件数据.而在Node.js中,设置好响应头后,读取文件流,再使用".pipe()"方法将流转接到响应对象Response就可以实现一个简单的文件下载服务器. 1. 文件下载介绍 HTTP基于请求头和响应头实现状态交互,在得到服务器正确响应状态后,而客户端首先会解析响应头,并根据响应头来接收和展示数据(响应体).对于文件下载来说,其实现过程如下: 1.客户端发起文

  • Node.JS段点续传:Nginx配置文件分段下载功能的实现方法

    Html5 提供了一个新的 Range 标签来实现文件的分段下载.在Node.JS中可以配置这个标签来实现文件的分段下载. Header标签 请求 Request Header: 下载 3744 以后的文件内容 range: bytes=3744- 返回 Response Header: 文件总长 15522643 个字节 accept-ranges': 'bytes' content-range': 'bytes */15522643' Nginx配置 首先要配置Nginx支持range标签返

  • 基于nodejs+express4.X实现文件下载的实例代码

    之前写了一个关于基于nodejs+express4.X实现文件下载实例,最近需要回顾,就顺便发到随笔上了 在nodejs的express框架中,下载变得非常简单,就一个方法,res.download() 首先express命令行生成项目基本框架: 不会的看这里:http://www.jb51.net/article/118537.htm 看看api 看看源码 其实底层还是res.sendFile(),头部也已经设定好了. 测试 1.在public文件夹下放入1.jpg图片和1.txt文件 2.在

  • node.js使用express框架进行文件上传详解

    关于node.js使用express框架进行文件上传,主要来自于最近对Settings-Sync插件做的研究. 目前的研究算是取得的比较好的进展. Settings-Sync中通过快捷键上传文件,其实主要还是请求后端接口. 于是我便使用node.js模拟一个服务,这个服务其实就相当于github api(Settings-Sync实际请求的接口,比如token验证,gist存储创建等都是来自github 对应的api). 话不多说,直接代码贴起讲解: 1.创建一个node.js项目(这里我以ex

  • node.js(express)中使用Jcrop进行图片剪切上传功能

    需求说明 简单来说就是要实现用户上传头像,并且要保存用户裁切后的部分作为用户头像. 第一步,选择图片: 第二步,在弹窗页面中展现并进行裁切: 第三步,点击"保存",上传服务器. 实现过程 说来有点坎坷,相当于做了2遍,走了弯路. 第1遍是用户一选择图片,就进行了上传,然后返回一个地址,所以在弹层上展现的图片已经是服务器上的图片了,然后进行裁切,再保存. 第2遍找到的一个方法,是在第1遍做到裁切处理时候想到的,即弹层展现的是用户机器上选择的图片,不用先上传,但是用image/base64

  • Node.js 使用request模块下载文件的实例

    前言 Node.js是JavaScript的一个解析器,可以运行js文件,今天就是简单说一下如何使用Node.js下的request模块下载文件. 1.request 模块下载 npm install request 首先建一个文件夹,在控制台进入该文件夹执行这个命令之后就会在当前文件夹下载request模块了 2.代码编写 var request = require('request'); var fs = require('fs'); /* * url 网络文件地址 * filename 文

  • Node.js的Express框架使用上手指南

    Express介绍 npm提供了大量的第三方模块,其中不乏许多Web框架,比如我们本章节要讲述的一个轻量级的Web框架 --- Express. Express是一个简洁.灵活的node.js Web应用开发框架, 它提供一系列强大的功能,比如:模板解析.静态文件服务.中间件.路由控制等等,并且还可以使用插件或整合其他模块来帮助你创建各种 Web和移动设备应用,是目前最流行的基于Node.js的Web开发框架,并且支持Ejs.jade等多种模板,可以快速地搭建一个具有完整功能的网站. 好,下面我

  • 使用nodejs+express实现简单的文件上传功能

    1.建立express项目 express -e nodejs-uploadfile 2.下载multer中间件 npm i multer or yarn multer 3.在routes/index.js中引用multer,由于还要使用到文件操作,还要引用fs模块,并指定文件上传目录 const multer = require('multer'); const fs = require('fs'); const UPLOAD_PATH = './uploads' 单文件上传: index.h

  • nodejs+express实现文件上传下载管理网站

    nodejs+express-实现文件上传下载管理的网站 项目Github地址:https://github.com/qcer/updo 后端:基于nodejs的express的web框架. 前端:bootstrap框架+vuejs.jquery等js库 功能点: dronzone.js实现文件拖拽上传.下载,可自定义传输容量. vuejs实现表格双向数据绑定. jquery.form.min.js表单插件,升级表单,实现表单提交回调. 纯css+jQuery实现一键返回顶部. 简单的ajax异

  • 从零开始学习Node.js系列教程之基于connect和express框架的多页面实现数学运算示例

    本文实例讲述了Node.js基于connect和express框架的多页面实现数学运算.分享给大家供大家参考,具体如下: 1.使用connect框架 .use方法用于绑定中间件到connect服务器,它会配置一系列在接到请求时调用的中间件模块,此例中我们要配置的中间件有favicon logger static router app.get/post/put        写法:app.requestName('path', function(req, res, next){}); app-co

  • Node.js + express实现上传大文件的方法分析【图片、文本文件】

    本文实例讲述了Node.js + express实现上传大文件的方法.分享给大家供大家参考,具体如下: 对于大文件的上传我们首先要引入一个叫做 multer 的库: npm install --save multer 关于这个库,大家可以查阅官方文档: 点击跳转 https://www.npmjs.com/package/multer 我们先将库引入我们的项目中: var multer = require('multer') var upload = multer({ dest: 'upload

  • node.js express框架简介与实现

    前言 之前学习过node.js接触过express框架,最近为了编写一个mock server正好用到了express.下面正好就跟大家介绍一下关于express. 今天的内容主要围绕这么几个方面? express框架初步介绍 express框架中的app.use和app.get/app.post mock server 介绍 mock server的实现思路 一.express框架初步介绍 关于express框架的介绍,这里我引用菜鸟教程的简介: Express是一个简洁而灵活的node.js

随机推荐