天天看点

nodejs 之文件上传

现在大多数的文件上传都是这样的流程,客户端->http->服务器->ftp->CDN服务器,下面按照这个流程来讲解一下文件上传过程:

首先客户端发起http请求,使用form Data格式上传文件数据,服务器端接到请求,把文件保存到一个临时文件夹中,这里我们用的是 nodejs 的 multer 模块,该模块功能很强大,

具体怎么使用请打开传送门 https://github.com/expressjs/multer,我贴一下我的代码:

var cpUpload = upload.fields([{name: 'avatar',maxCount: 1 }, {name: 'images',maxCount: 4 }]);
var base = 'tmp/uploads';const fs = require('fs');
const logger = require('../../core/lib/logger')();
const multer = require('koa-multer');
const asyncUploadFtp = require('../lib/ftp')
const cryptoSimple = require('../../core/util/cypto-simple');
const employeeModel = require('../model/employee');

// multer上传文件配置
const storage = multer.diskStorage({
    destination:'./tmp/uploads',
    filename : function(req, file, cb){
        let ext = file.originalname.substring(file.originalname.lastIndexOf('.') + 1);
        cb(null,cryptoSimple.getMd5(file.originalname +Date.now()) +'.' + ext)
    }
})
const upload = multer({ 
    storage: storage, 
    limits: { fileSize: 1024 * 1024 * 2 },
    fileFilter : (req,file, cb) => {
        //过滤jpg/jpeg/png图片除外的文件
        if(/.+[jpg|jpeg|png]$/.test(file.originalname)){
            cb(null,true);
        }else{
            cb(null,false)
        }
    } 
});
var cpUpload = upload.fields([{name: 'avatar',maxCount: 1 }, {name: 'images',maxCount: 4 }]);
var base = 'tmp/uploads';
           

调用cpUpload方法即可上传文件,我用的是koa2框架,ctx.req.files即可得到上传的文件信息,这时tmp/loads文件夹下已经可以发现我们上传的文件了

服务器上传到CDN服务器用的ftp协议,用的是ftp-client模块,直接上代码

const _ = require('lodash');
const logger = require('../../core/lib/logger')();
var FtpClient = require('ftp-client');
var config = {
    host: '*.*.*.*',
    port: 21,
    user: '***',
    password: '***'
};
var base = 'tmp/uploads';
var source = base + '/**';
var target = 'hd/static/' + base;
var options = {
    logging: 'basic'
};
var upOption = {
    baseDir: base,
    overwrite: 'older'
}
module.exports =function asyncUploadFtp() {
    return new Promise((resolve,reject)=> {
        var fct = new FtpClient(config,options);
        fct.connect(function(){
            fct.upload(source,target, upOption, (result)=>{
                fct.ftp.end();
                if (_.isEmpty(result.errors) ===false) {
                    reject(result.errors);
                }
                resolve()
            })
        })
    }).catch(err=> logger.error(err));
};
           
所有的FTP服务器都是需要帐号和密码才能登录的。不过有相当一部分FTP服务器提供了匿名登录,对于这些服务器我们可以使用通用的帐号和密码登录(通常是帐号Anonymous密码anonymous),也许你登录这些FTP服务器是没有提示你输入帐号和密码,实际上Windows或者FTP软件自动帮你完成了匿名登陆操作。   还有一部分FTP服务器出于各种原因,没有提供匿名登录,那么你就需要手工登录了.      
下面比较一下http和ftp上传文件的区别:      

1.FTP

(1)FTP比HTTP复杂

FTP和HTTP一样都是Internet上广泛使用的协议,用来在两台计算机之间互相传送文件。相比于HTTP,FTP协议要复杂得多。复杂的原因,是因为FTP协议要用到两个TCP连接,一个是命令链路,用来在FTP客户端与服务器之间传递命令;另一个是数据链路,用来上传或下载数据。

(2)FTP协议有两种工作方式:PORT方式和PASV方式,中文意思为主动式和被动式。

PORT(主动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路。当需要传送数据时,客户端在命令链上用PORT命令告诉服务器:“我打开了XXXX端口,你过来连接我”。于是服务器从20端口向客户端的XXXX端口发送连接请求,建立一条数据链路来传送数据。

PASV(被动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路。当需要传送数据时,服务器在命令链上用PASV命令告诉客户端:“我打开了XXXX端口,你过来连接我”。于是客户端向服务器的XXXX端口发送连接请求,建立一条数据链路来传送数据。

从上面可以看出,两种方式的命令链路连接方法是一样的,而数据链路的建立方法就完全不同。而FTP的复杂性就在于此。

2.上传大文件

Ftp有明显的天生的优势,不需要将文件全部载入内存中,http在这方面就比较薄落了, 当然也有人实现了分块http上传,但总体来说http上传对于大文件不适合,多大算大呢?,在局域网中,个人认为超过了500M的文件就不适合使用http协议来上传了。

3.上传小文件

非常适合http协议来上传,因为简单,而且可以实现更精细的控制,权限控制比ftp要简单的多。而且

ftp每次上传文件都要建立一个新的ftp连接,对一个HTTP会话来讲,客户端可以维护一个单个的连接并使用它进行任意数量的数据传输。FTP每次有数据的都需要和服务器创建一个新的连接。而且需要两个TCP连接,重复的创建新的连接带来的体验并不好,因为每次创建连接都必须让双方握手验证,这消耗了很多时间。所以上传小文件时http会更合适