express でファイルアップロード
参考:
- http://tjholowaychuk.com/post/12943975936/connect-1-8-0-multipart-support
- https://github.com/felixge/node-formidable/issues/108
- http://www.hacksparrow.com/handle-file-uploads-in-express-node-js.html
nodeでファイルアップロードする方法、難しい順。
1. req.on('data') で、ちょこちょこデータを溜め込んでいく。(僕には無理っぽい)
2. それを楽にするformidable というモジュール。丁寧に 'progress' というイベントまでemit してくれる。
3. express のapp.configure で app.use(express.bodyParser()) していたら、req.files で更に簡単にupload できる。formidable は必要なくなる。
express でファイルアップロードを書く
ただアップロードする他に、ファイルを配置するディレクトリを作ったり、DBにファイルを保存したりしてみました。
でも、ほとんどhttp://www.hacksparrow.com/handle-file-uploads-in-express-node-js.htmlの内容です。
html:
<form action="/upload" method="post" enctype="multipart/form-data"> <input type="file" name="upfile"/> <input type="submit" value="送信"/> </form>
server:
/* app.js */ var TMP_DIR = './tmp'; app.configure(function(){ . . app.use(express.bodyParser({ uploadDir: TMP_DIR /* 追記 */ })); . . }); . . app.get('/', routes.index); app.post('/upload', routes.upload); /* 追記 */ .
/* route/index.js */ /* * GET home page. */ // Require modules. var mkdirp = require('mkdirp') /* $ npm install mkdirp */ , fs = require('fs') , _ = require('underscore') , path = require('path') , db = require('../resources/server/db'); // Pad string function. _.mixin({ pad: function (target, length) { var padStr = '0'; var target = target.toString(); var result = target; var num = length - target.length; for (var i=0; i<num; i++) { result = padStr + result; } return result; } }); // Handler for GET '/'. exports.index = function(req, res){ db.Files.find({}, [], {}, function (err, files) { if (err) return; res.render('index', { title: 'Express' , IS_PRODUCTION: process.env.NODE_ENV === 'production' // new , files: files ? files : [] }) }); } // Handler for POST '/upload'. var UPLOAD_BASEPATH = __dirname + '/../public/uploaded/'; var getUpfileDir = function () { var d = new Date(); return d.getFullYear() + _.pad(d.getMonth() + 1, 2) + '/' + _.pad(d.getDate() + '/', 2); }; exports.upload = function(req, res){ var upfile = req.files.upfile if (upfile) { var tmpPath = './' + upfile.path; var saveDir = getUpfileDir(); var dir_ = path.normalize(UPLOAD_BASEPATH + saveDir); if (!path.existsSync(dir_)) mkdirp.sync(dir_); var savePath = saveDir + path.basename(tmpPath) + path.extname(upfile.name); var targetPath = path.normalize(UPLOAD_BASEPATH + savePath); fs.rename(tmpPath, targetPath, function (err) { if (err) throw err; var file = new db.Files(); file = _.extend(file, { title: req.body.title , name: upfile.name , type: upfile.type , path: savePath , createdAt: new Date() }); file.save(function (err) { res.redirect('/'); }); }); } };
/* resources/server/db.js */ // Setting mongoose. var mongoose = require('mongoose'); var FileUploadSchema = new mongoose.Schema({ title: String , name: String , type: String , path: String , createdAt: Date }); mongoose.model('Files', FileUploadSchema) mongoose.connect('mongodb://localhost/fileupload') exports.Files = mongoose.model('Files')
その他
- <input type="file" name="upfile" multiple="multiple" / >と書くと、複数ファイルを同時にアップロードできる(対応ブラウザが限られると思います、ご注意ください)
- その場合は req.files.upfile がオブジェクトじゃなくて配列になる。