更多内容参考系列文章: nodejs系列提纲
作为本blog的需求,上传图片始终是要支持的。但是呢,久久未动,以为麻烦,尽管诸多文章显示非常简单。昨天晚上终于下定决心解决它。果然简单异常,但是在本地测试成功之后发现部署到CloudFoundry却不能正常运行,原来还有小细节没有注意到。下面一一道来。
1. 准备工作
首先你要知道怎么用NodeJs下面的Web框架Express,这是一个比较简单、使用广泛的框架,入门很简单。本ramonblog就是用它搭建的。Express的View是用jade语法的,这个你也得懂一点。是不是学的东西有点多了?不用太理解,开始的时候都是抄的,抄得多也就懂了。
然后呢,我们就用可以准备我们的upload.jade了,这里仅仅是包含了一个简单的表单,里面一个file input元素和一个submit元素。
div
form(method="post", enctype="multipart/form-data")
input(type="file", name="displayImage")
input(type="submit", name="submit", value="Submit")
2. 让它工作吧
之所以Express底下上传文件非常简单,是因为Express的bodyParser中间件会在解析request请求的时候,将“multipart/form-data”里面的file input对应的内容自动处理保存到默认的/tmp文件夹下面,而你可以通过req.files来获取所有的属性,其内容大概如下:
{ displayImage:
{
size: 18925,
path: '/tmp/47662e4853761e4b30b6c3a329980dac',
name: '2.jpg',
type: 'image/jpeg',
lastModifiedDate: Wed, 18 Jul 2012 17:01:44 GMT,
_writeStream:
{ path: '/tmp/47662e4853761e4b30b6c3a329980dac',
fd: 36,
writable: false,
flags: 'w',
encoding: 'binary',
mode: 438,
bytesWritten: 18925,
busy: false,
_queue: [],
drainable: true },
length: [Getter],
filename: [Getter],
mime: [Getter]
}
}
}
注意其中的displayImage是我们在form中定义的file的name,req.files.displayImage的path表示在服务器端的临时地址,name表示上传的原始文件名称,type则是文件类型了。提交之后的处理则如下:
var fs = require('fs');
var path = require('path');
function(req, res) {
//你可能需要修改相关的newPath到你自己的地址
var filePath = req.files.displayImage.path;
var extName = path.extname(req.files.displayImage.name);
var imageUrl = "/upload/" + path.basename(filePath) + extName;
var newPath = __dirname + "/../public" + imageUrl;
//把图片从临时文件夹复制到目的文件夹,当然最好删除临时文件
fs.readFile(filePath, function (err, data) {
if (err) {
res.send(err);
return;
}
fs.writeFile(newPath, data, function (err) {
if (!err) {
res.send({uploaded: true});
} else {
res.send(err);
}
});
});
}
注意,你可能需要自己修改newPath到你自己正确的地址。其次,如果想直接访问你上传的图片,需要把图片放置在Express指定的public文件夹下面,这样可以直接通过链接访问。
3. CloudFoundry上不能工作
很显然在CF的服务器上你不能写文件到 /tmp下面去。其实解决办法也很简单,就是把临时文件夹指定到你自己的应用下面去。譬如指定为应用下面的tmp文件夹,需要做的就是在你的app.js中增加如下的i配置:
app.use(express.bodyParser({
uploadDir: __dirname + '/tmp'
}));
这里要求的app.js就在应用的根目录下,这样__dirname就会是你的应用根目录。之后你就可以在CF上执行上传图片了。
更具体的代码可以参考本blog在github上面的代码:
https://github.com/flyingsky/node-blog/blob/master/views/demos/upload.jade
https://github.com/flyingsky/node-blog/blob/master/routes/demo.js