本文是翻译的一篇文章,原文地址:Handle File Uploads in Express (Node.js).
在NodeJS发展早期上传文件是一个较难操作的功能,随后出现了formidable。它开了一个好头,然而上传文件仍然不是那么容易。在此之后又出现了基于原文作者的教程(tutorial on handling POST requests in Express)而实现的工具connect-form。它让文件上传的过程显得简单了一些。
随着NodeJS社区的飞速发展,让上传文件这个功能变得简单得以实现肯定不会需要太长时间。现在这个功能已经得以实现—在ExpressJS中你可以很容易的上传文件。
在Express中上传文件时不再需要依赖其他的模块,文件上传可以很好工作于Express框架内。就像使用req.body一样,现在你可以使用req.files来获得你上传的文件中的具体信息。
如果你不需要指定上传文件的目录,那么你不需要对app.js做任何的改变,文件将默认上传到’/tmp’目录。但是如果你希望对你上传的文件指定特定目录,你仅仅需要修改一下内容:
app.use(express.bodyParser());
修改为 :
app.use(express.bodyParser({uploadDir:'./uploads'}));
这一配置项可以再ExpressJS的V2.5.4之后的版本中发现,具体可以参看ExpressJS的源代码,具体在express.bodyParser的第16行。在上面的示例中。文件将被上传到与express应用同级目录下的uploads目录中。
为了更好说明在POST过程中文件上传时一些细节,我们建立如下的一个表单提交页面:
<form method="post" enctype="multipart/form-data" action="/file-upload">
<input type="text" name="username">
<input type="password" name="password">
<input type="file" name="thumbnail">
<input type="submit">
</form>
服务端在处理上面的表单提交时的方法如下:
app.post('/file-upload', function(req, res, next) {
console.log(req.body);
console.log(req.files);
});
看看就是这么简单!
在上面的示例中,我们可以通过调用req.files.thumbnail对象来获得我们上传的文件的具体信息,对象的名称取决你上在form表单的定义。如上所示,我们使用的名称是thumbnail,因此我们可以通过req.files.thumbnail来获得它的信息。
一个文件包含以下常用的属性信息:
- size ---- 文件大小(bytes)
- path ---- 文件上传后的路径
- name ---- 文件的原始文件名称.
- type ----文件类型
针对上面的示例来说, 文件大小:req.files.thumbnail.size 文件类型: req.files.thumbnail.type 原文件名: req.files.thumbnail.name
需要注意的是,默认的上传目录或你指定的上传目录都只是临时目录,因此你还需要将上传的文件移动相应的文件目录。下面的示例代码演示了如何将上传的文件移动到’/images’目录下:
// 移动文件需要使用fs模块
var fs = require('fs');
app.post('/file-upload', function(req, res) {
// 获得文件的临时路径
var tmp_path = req.files.thumbnail.path;
// 指定文件上传后的目录 - 示例为"images"目录。
var target_path = './public/images/' + req.files.thumbnail.name;
// 移动文件
fs.rename(tmp_path, target_path, function(err) {
if (err) throw err;
// 删除临时文件夹文件,
fs.unlink(tmp_path, function() {
if (err) throw err;
res.send('File uploaded to: ' + target_path + ' - ' + req.files.thumbnail.size + ' bytes');
});
});
};
你可以将上传目录指定为任何你可以在当前操作系统环境下可以访问的目录。如果你希望这些文件可以被公开访问,你可以将文件拷贝到应用的静态目录’/public’下。需要注意的是,如果需要将文件拷贝到public或其子目录下,请确保文件夹存在,且可以被写入。否则会出现’Error: ENOENT, no such file’等异常信息。
现在在ExpressJS中上传文件将是一件非常简单的事情。如果你的原有应用需要使用文件上传,那么我建议你将应用升级到最新的ExpressJS框架,并且修改你的程序以保证功能可以正常工作。
app.post('/file-upload', function(req, res) {
// 获得文件的临时路径
var tmp_path = req.files.thumbnail.path;
// 指定文件上传后的目录 - 示例为"images"目录。
var target_path = './public/images/' + req.files.thumbnail.name;
// 移动文件
fs.rename(tmp_path, target_path, function(err) {
if (err) throw err;
// 删除临时文件夹文件,
fs.unlink(tmp_path, function() {
if (err) throw err;
res.send('File uploaded to: ' + target_path + ' - ' + req.files.thumbnail.size + ' bytes');
});
});
这个方法中,在执行哪一步时文件已经上传完毕?是rename前就上传完毕了嘛?如果不是的话(不同步)不就错了?
是的。因为在express会先处理上传的文件,并且将对象数据产生好放入req.files中。然后再路由请求到file-upload方法。要验证是不是这样,可以做个小实验嘛。光看代码并不能解答疑惑。并且这个上传是基于Express的,那么肯定express是作处理的。
小弟刚刚开始接触node 有点弱弱的问题想问问 首先是 html文件如何转换成 jade格式 比如这句
<form method="post" enctype="multipart/form-data" action="/file-upload"> 应该如何写成jade格式呢?app.post('/file-upload’, function(req, res) {…}
还有以上这段代码 是直接加到app.js中就可以吗?
form(method="post", enctype="multipart/form-data", action="/upload")
fieldset
legend General
p
label(for="user[pic]") Picture:
input(type="file", name="pics")
p.buttons
input(type="submit", value="Save")
在windows下,如果你的node安装在非系统盘,按照上文给出的的方法,应该会出现诸如 Error: EXDEV, rename … 之类的错误。
这是因为express默认上传临时目录是在系统盘,而windows下rename不可以跨区操作。查看了下nodeclud的代码,发现它是用下面的方式修改express默认上传临时目录:
var ndir = require('ndir');
var mod = require('express/node_modules/connect/node_modules/formidable');
var upload_path = path.join(path.dirname(__dirname), 'public/user_data/images');
ndir.mkdir(upload_path, function (err) {
if (err) {
throw err;
}
mod.IncomingForm.UPLOAD_DIR = upload_path;
});
用webstorm运行了下。。。有报错 Error: EXDEV, rename ‘C:\DOCUME~1\WB-YAN~1\LOCALS~1\Temp\370f31ad9ec2046b7e986eea8e50cb9c’ 这个是怎么回事的呀
用webstorm运行了下。。。有报错 Error: EXDEV, rename ‘C:\DOCUME~1\WB-YAN~1\LOCALS~1\Temp\370f31ad9ec2046b7e986eea8e50cb9c’ ------我的node安装在系统盘上的,初了这个还有其他的原因吗?
按照顶楼提示改了文件上传目录为files,但有时候会出现下面的错误 Error:EPERM,rename 'D:\chat\chat\files\e4fbacfeb6dd020732c592e7621d6。有时候挺正确。不知道哪里出问题了。请指教
有个问题,怎么阻止上传,总不能让用户无限制上传吧,服务器要爆的。
<form method="post" enctype="multipart/form-data" action="/file-upload"> <input type="text" name="username"> <input type="password" name="password"> <input type="file" name="thumbnail"> <input type="submit"> </form>如果去掉enctype="multipart/form-data" console.log(req.body); console.log(req.files); 结果分别为: {username:"abc",password:"123" ,thumbnail:"a.txt">} undefined 哪里的问题嘞?