nodejs 文件上传/下载功能实现
09 March 2014
分三个部分:
nodejs作为http client上传文件到服务器上
nodejs作为http server处理文件上传的post请求
nodejs作为http server处理文件下载的请求
1. 上传文件到服务器
测试环境准备,使用formidable提供文件上传处理的测试环境。
var formidable = require('formidable'),
http = require('http'),
util = require('util');
http.createServer(function(req, res) {
if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
// parse a file upload
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
res.end(util.inspect({fields: fields, files: files}));
});
return;
}
// show a file upload form
res.writeHead(200, {'content-type': 'text/html'});
res.end(
'<form action="/upload" enctype="multipart/form-data" method="post">'+
'<input type="text" name="title"><br>'+
'<input type="file" name="upload" multiple="multiple"><br>'+
'<input type="submit" value="Upload">'+
'</form>'
);
}).listen(8000);
下面是nodejs的发送上传文件请求的代码,假设用于上传的文件testUpload.txt位于当前目录下(uploadFilePath指定):
var fs = require("fs");
var path = require("path");
var http = require("http");
var uploadOption = {
host: "127.0.0.1",
port: "8000",
path: "/upload",
method: 'post'
};
var formFieldName = "files";
var uploadFilePath = "./testUpload.txt";//待上传的文件路径
var boundaryKey = "NodeFormBoundaryKey";//multipart的part之间的界定符
var request = http.request(uploadOption, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function(chunk) {
console.log('BODY: ' + chunk);
});
res.on('end', function(err) {
console.log("UPLOAD DONE");
});
});
request.on("error", function(e) {
console.log('upload Error: ' + e.message);
})
request.setHeader('Content-Type', 'multipart/form-data; boundary="' + boundaryKey + '"');//设置编码方式multipart/form-data和各个part之间的界定符
var filename = path.basename(uploadFilePath);
var part = [];
part.push('--' + boundaryKey);//part开始界定符
part.push('Content-Type: application/octet-stream');
part.push('Content-Disposition: form-data; name="' + formFieldName + '"; filename="' + filename + '"');
part.push('Content-Transfer-Encoding: binary');
part.push('\r\n');
request.write(part.join('\r\n'));
var readStream = fs.createReadStream(uploadFilePath, {
bufferSize: 4 * 1024
});
readStream.on('end', function(err) {
if (err) {
console.error(err);
return;
}
request.end('\r\n--' + boundaryKey + '--');//请求体结束标记
console.log("finish sending file " + uploadFilePath + ' content');
});
readStream.pipe(request, {
end: false //readStream 读完之后,还要再补充一行请求体结束标记
});
关键点:multipart/form-data和boundary概念,这个可以看nodejs-post文件上传原理详解,文中有form和multipart相关的HTTP协议说明。
2. 处理文件上传请求
上面已经提到的formidable,是一个专业处理post类型请求体,特别是文件上传的请求体的nodejs库。
不依赖formidable,自己手动写代码解析post请求体的方法有待补充。
3. 处理文件下载请求
这个是三个问题中处理起来最简单的:
var fs = require("fs");
var path = require("path");
var http = require("http");
http.createServer(function(req, res) {
if (req.url == '/download') {
var downloadFilePath = "./testDownload.js";
var filename = path.basename(downloadFilePath);
var filesize = fs.readFileSync(downloadFilePath).length;
res.setHeader('Content-Disposition','attachment;filename=' + filename);//此处是关键
res.setHeader('Content-Length',filesize);
res.setHeader('Content-Type','application/octet-stream');
var fileStream = fs.createReadStream(downloadFilePath,{bufferSize:1024 * 1024});
fileStream.pipe(res,{end:true});
return;
}
// show a file download link
res.writeHead(200, {'content-type': 'text/html'});
res.end('点击此处开始下载');
}).listen(8000);
浏览器能把http响应当做文件下载来处理,主要是依据响应头中的Content-Disposition: attachment;filename=testDownload.js来判断的。
相关链接:
blog comments powered by Disqus