備忘録です.
Node.js と express,formidable を使って,POSTでファイルのアップロードを受け付ける処理を書きました.
環境
- MacOSX (10.9)
- Node.js (v0.10.29)
- npm (1.4.14)
- express (3.5.1)
- formidable (1.0.15)
- jQuery (1.11.0)
準備
まず,express を使用してプロジェクトを生成します.
express -e ejs sample
,cd sample && sudo npm install
この時,express は app.js に app.use(express.json())
と app.use(express.urlencoded())
を記述します.
これにより,Content-Type が application/json
と application/x-www-form-urlencode
のものを解釈するようになります.
ただし,ファイルを含んだPOSTではContent-Typeがmultipart/form-data
となるためこのままでは解釈できません.
以前は,app.use(multipart())
といったように指定することで対応していましたが,現在はwarningが出るようになっています.
そこで,formidable( https://github.com/felixge/node-formidable )を使用することで対処します.
インストールはnpmからsudo npm install formidable@latest
で行います.
実際の動きはサンプルコードを使って説明します.
サンプルコード
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>post test</title>
</head>
<body>
<form action="http://localhost:3000/post" method="POST" enctype="multipart/form-data">
<input type="text" name="name" value="" placeholder="">
<input type="file" name="file">
<input type="submit" name="submit" value="送信">
</form>
</body>
</html>
post.html は単純なテキストとファイルをPOSTで送信するものです.
(ほんとはejsとかで用意してapp.jsに追記ってやったほうがいいけどめんどくさかったから端折った)
/**
* Module dependencies.
*/
var express = require('express');
var routes = require('./routes');
var user = require('./routes/user');
var http = require('http');
var path = require('path');
var app = express();
// add 1
var formidable = require('formidable');
var fs = require('fs');
var util = require('util');
// ---
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(express.favicon(__dirname + '/public/favicon/fav.ico'));
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
app.get('/', routes.index);
app.get('/users', user.list);
// add 2
app.post('/post', function(req, res) {
var form = new formidable.IncomingForm();
form.encoding = "utf-8";
form.uploadDir = "./public/images"
form.parse(req, function(err, fields, files) {
res.writeHead(200, {'content-type': 'text/html'});
res.write('received upload:\n\n');
res.end(util.inspect({fields: fields, files: files}));
var oldPath = './' + files.file._writeStream.path;
var newPath = './public/images/' + files.file.name;
fs.rename(oldPath, newPath, function(err) {
if (err) throw err;
});
});
});
// ---
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
app.js では2つの箇所に追記をしています.
まず,add 1 です.
ここでは,add 2 での処理のために formidableとfs, util を使用する準備をしています.
次に,add 2 です.
add 2 にはlocalhost:3000/post
にPOSTが来た時の処理を書いています.
ここでは,まず,文字エンコーディングとファイルをアップロードするディレクトリの指定を行っています.
次に,form.parse
で 受け取ったデータの解釈を行います.
form.parse
ではpost.html
の例だと input type='text'
の内容がfields に,input type='file'
の内容がfiles に渡されます.
form.parse
の function
では,前半3行でクライアントへのレスポンス,
後半で./public/images/
に保存されたファイルについて,エンコードされたファイル名から基のファイル名へとリネームを行っています.
filesが持つプロパティ,例えば基のファイル名はfiles.file._writeStream.path
といったように参照できます.
ひとこと
今日からNode.js days にもどるんるん.あ、あとjQuery Ajax で送った時も基本一緒です.