NodeJS的图片或文件上传,如果使用express框架实现起来非常简单,但是,对于那些已经使用非express框架创建集群的应用场景,混用express框架会带来诸多问题,还是要基于现有技术解决。这其中的重点就在于如何识别各个参数,并将文件流数据分离出来,下面先来看看上传数据的格式:
[回车]
Content-Disposition: form-data; name="text"[回车]
[回车]
[回车]
------WebKitFormBoundaryXXXXXXX[回车]
Content-Disposition: form-data; name="avatar"; filename="111.jpg"[回车]
Content-Type: image/jpeg[回车]
文件流数据[回车]
------WebKitFormBoundaryXXXXXX[回车]
第一步,将传入的数据变成二进制数组
第二步,根据\r\n分离数据和报头
第三步,根据上传数据的格式,并获得参数名称,参数值,以及其他属性。上传数据格式中以“------WebKitFormBoundary”开头的字符串是各参数信息的分隔符,每个参数至少有三组数据,Content-Disposition,Content-Type以及参数值。
第四步,将文件或图片数据保存到本地,并将文件URI返回给Client
// 上传文件函数
var upload = function(request, response){
var chunks = [];
var size = 0;
request.on('data' , function(chunk){
chunks.push(chunk);
size+=chunk.length;
});request.on("end",function(){
var buffer = Buffer.concat(chunks , size);
if(!size){
response.writeHead(404);
response.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);
log(i);
}
}
var params = new Map();
for ( var i = 0 ; i < rems.length-1 ; i++ ) {
// 从数据流中取出每一个被\r\n分离的数据,并进行处理
var line = buffer.slice(rems[i]+2,rems[i+1]).toString();
if ( line.startWith("------WebKitFormBoundary") ) {
continue;
} else if ( line.startWith("Content-Disposition: form-data;") ) {
var parts = line.split(";");
// 获得param的name
var name = parts[1].trim().split("=")[1].replace(/\"/g,"");
//如果参数存在文件名,获得文件名
var fileName;
if ( parts.length > 2 ){
fileName = parts[2].trim().split("=")[1].replace(/\"/g,"");
}
//log(">>> name = " + name + " >>>> filename = " + fileName);
i++;
var type = buffer.slice(rems[i]+2,rems[i+1]).toString();
type = type.substr("Content-Type:".length).trim();
//log(">>> type = " + type);
if ( type != undefined ){
i++;
if ( type == "image/jpeg" ){
if ( fileName != undefined ) {
var imgObject = new Object();
imgObject.type = "img";
imgObject.data = buffer.slice(rems[i]+4,rems[rems.length-2]);
imgObject.path = './upload/'+fileName;
imgObject.size = rems[rems.length-2] - (rems[i]+2);
params.set("upload_file",imgObject);
log("图片路径:" + imgObject.path + ";图片大小:"+imgObject.size);
} else {
// 将请求中的图片设置为空
log("上传图片为空");
params.set(name,undefined);
}
} else {
var value = buffer.slice(rems[i]+2,rems[i+1]).toString();
// 将请求中的参数提取出来
params.set(name,value);
log("参数名称:"+name + " ;参数值:"+value );
}
}
}
}
// 保存文件
var fileObj = params.get("upload_file");
fs.writeFileSync(fileObj.path, fileObj.data);
var obj = new Object();
obj.fileId = uuid.v1();
obj.filePath = fileObj.path;
obj.createdTime = new Date();
response.end(JSON.parse(obj));
});
});
}