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