node.js 文件上传

Posted by 姚飞亮 on 2019-06-23

node.js文件上传,前后端处理

后端

总结两种方式:原生和引用三方模块(直举例介绍一种模块)

原生

直接上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
const express = require('express');
const router = express.Router();
const fs = require('fs');
const path = require('path');
router.post('/ajaxfiles', function(req, res, next) {
var chunks = [];
var size = 0;
req.on('data' , function(chunk){
chunks.push(chunk);
size+=chunk.length;
});
req.on("end",function(){
var buffer = Buffer.concat(chunks , size);
if(!size){
res.writeHead(404);
res.end('');
return;
}
var rems = [];
//根据\r\n分离数据和报头
for(var i=0;i<buffer.length;i++){
var v = buffer[i];
var v2 = buffer[i+1];
if(v==13 && v2==10){
rems.push(i);
}
}
//图片信息
var picmsg_1 = buffer.slice(rems[0]+2,rems[1]).toString();
var filename = picmsg_1.match(/filename=".*"/g)[0].split('"')[1];
//图片数据
var nbuf = buffer.slice(rems[3]+2,rems[rems.length-2]);
var temppath = path.resolve(__dirname, '..');
var targetFile = path.join(temppath,'public/images/uploadFile');
console.dir(targetFile)
targetFile = targetFile+'/'+filename;
fs.writeFileSync(targetFile , nbuf);
console.log("保存"+filename+"成功");
res.writeHead(200, { 'Content-Type': 'text/html;charset=utf-8'});
res.end(JSON.stringify({success:true,url:targetFile}));
});
});

formidable模块

详细见npmjs https://www.npmjs.com/package/formidable

安装

1
npm i -S formidable

例1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const formidable = require("formidable");
const fs = require('fs');
const path = require('path');

router.post('/upload', function(req, res) {
var form = new formidable.IncomingForm();
var temppath = path.resolve(__dirname, '..');
console.dir(temppath)
var targetFile = path.join(temppath,'public/images/uploadFile');
console.dir(targetFile)
form.uploadDir = targetFile;
form.parse(req, function(error, fields, files){
if(error) throw error;
var fileName = Date.parse(new Date());
let oldpath=files.file.path;
let newpath = targetFile + '/' + fileName +files.file.name;
fs.rename(oldpath, newpath,function(err){
if(err) throw err;
res.send( {code:1,'imageURL' : '/images/uploadFile/'+ fileName +files.file.name});
});
});
});

例2 多文件上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
router.post('/upload', function(req, res, next) {//对应前端请求的路径,请求方法
var form = formidable.IncomingForm({
encoding : 'utf-8',//上传编码
uploadDir : "public/images/uploadFile",//上传目录,指的是服务器的路径,如果不存在将会报错。
keepExtensions : true,//保留后缀
maxFieldsSize : 2 * 1024 * 1024//byte//最大可上传大小
});

var allFile=[];
form.on('progress', function(bytesReceived, bytesExpected) {//在控制台打印文件上传进度
var progressInfo = {
value: bytesReceived,
total: bytesExpected
};
console.log('[progress]: ' + JSON.stringify(progressInfo));
//res.write(JSON.stringify(progressInfo));
})
.on('file', function (filed, file) {
var date = new Date();
var ms = Date.parse(date);
file.fieldNamedate=ms;
allFile.push([filed, file]);//收集传过来的所有文件
})
.on('end', function() {
//res.end('上传成功!');
console.dir('上传成功!');
let pathfileurls=[];
allFile.forEach(function(file,index){
var types = file[1].name.split('.');
pathfileurls.push({name:file[1].name,url:form.uploadDir+"/"+types[0]+'_'+file[1].fieldNamedate+"."+String(types[types.length-1])})
});
console.dir(pathfileurls);
console.dir(allFile);
res.end(JSON.stringify({success:true,pathfileurls:pathfileurls}));
})
.on('error', function(err) {
console.error('上传失败:', err.message);
next(err);
})
.parse(req,function(err, fields, files){
if(err){
console.log(err);
}
allFile.forEach(function(file,index){
var fieldName=file[0];
var types = file[1].name.split('.');
// var date = new Date();
// var ms = Date.parse(date);
fs.renameSync(file[1].path,form.uploadDir+"/"+types[0]+'_'+file[1].fieldNamedate+"."+String(types[types.length-1]));//重命名文件,默认的文件名是带有一串编码的,我们要把它还原为它原先的名字。

});
});
});

前段

js原生

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//图片上传
var xhr;
//上传文件方法
function UpladFile(fileObj) {
//var fileObj = document.getElementById("file").files[0]; // js 获取文件对象
var url = "http://localhost:3000" + "/ajaxfiles"; // 接收上传文件的后台地址
var form = new FormData(); // FormData 对象
form.append("file", fileObj); // 文件对象
xhr = new XMLHttpRequest(); // XMLHttpRequest 对象
xhr.open("post", url, true); //post方式,url为服务器请求地址,true 该参数规定请求是否异步处理。
xhr.onload = uploadComplete; //请求完成
xhr.onerror = uploadFailed; //请求失败
xhr.upload.onprogress = progressFunction;//【上传进度调用方法实现】
xhr.upload.onloadstart = function () {//上传开始执行方法
ot = new Date().getTime(); //设置上传开始时间
oloaded = 0;//设置上传开始时,以上传的文件大小为0
};
xhr.send(form); //开始上传,发送form数据
}

//上传成功响应
function uploadComplete(evt) {
//服务断接收完文件返回的结果
console.dir(evt)
var data = JSON.parse(evt.target.responseText);
if (data.success) {
alert("上传成功!");
} else {
alert("上传失败!");
}

}
//上传失败
function uploadFailed(evt) {
alert("上传失败!");
}
//取消上传
function cancleUploadFile() {
xhr.abort();
}
//上传进度实现方法,上传过程中会频繁调用该方法
function progressFunction(evt) {
/* var progressBar = document.getElementById("progressBar");
var percentageDiv = document.getElementById("percentage"); */
// event.total是需要传输的总字节,event.loaded是已经传输的字节。如果event.lengthComputable不为真,则event.total等于0
if (evt.lengthComputable) {//
console.dir(evt.total)
console.dir(evt.loaded)
console.dir(Math.round(evt.loaded / evt.total * 100) + "%")
/* progressBar.max = evt.total;
progressBar.value = evt.loaded;
percentageDiv.innerHTML = Math.round(evt.loaded / evt.total * 100) + "%"; */
}
// var time = document.getElementById("time");
var nt = new Date().getTime();//获取当前时间
var pertime = (nt - ot) / 1000; //计算出上次调用该方法时到现在的时间差,单位为s
ot = new Date().getTime(); //重新赋值时间,用于下次计算
var perload = evt.loaded - oloaded; //计算该分段上传的文件大小,单位b
oloaded = evt.loaded;//重新赋值已上传文件大小,用以下次计算
//上传速度计算
var speed = perload / pertime;//单位b/s
var bspeed = speed;
var units = 'b/s';//单位名称
if (speed / 1024 > 1) {
speed = speed / 1024;
units = 'k/s';
}
if (speed / 1024 > 1) {
speed = speed / 1024;
units = 'M/s';
}
speed = speed.toFixed(1);
//剩余时间
var resttime = ((evt.total - evt.loaded) / bspeed).toFixed(1);
/* time.innerHTML = ',速度:'+speed+units+',剩余时间:'+resttime+'s';
if(bspeed==0) time.innerHTML = '上传已取消'; */
let time_html = ',速度:' + speed + units + ',剩余时间:' + resttime + 's';
if (bspeed == 0) time_html = '上传已取消';
console.dir(time_html);
}
1
UpladFile(document.getElementById('files').files[0]);

form表单

1
2
3
4
5
<form action="/ajaxfiles" method="post" enctype="multipart/form-data">
<h2>上传</h2>
<input type="file" name="logo">
<input type="submit" value="提交">
</form>

其他前段框架组件

例如 layui.upload 组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var uploadInst = upload.render({
elem: '#test1'
, url: '/upload/'
, before: function (obj) {
//预读本地文件示例,不支持ie8
obj.preview(function (index, file, result) {
$('#demo1').attr('src', result); //图片链接(base64)
});
}
, done: function (res) {
//如果上传失败
console.dir(res)
if (res.code > 0) {
//return layer.msg('上传失败');
$("input[name='url']").val(res.imageURL);
}
//上传成功
}
, error: function () {
//演示失败状态,并实现重传
}
});


Ω