LoginSignup
30
28

More than 5 years have passed since last update.

Node.js + express + formidable でファイルアップロードを受け付ける

Posted at

備忘録です.
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 samplecd sample && sudo npm install

この時,express は app.js に app.use(express.json())app.use(express.urlencoded()) を記述します.
これにより,Content-Type が application/jsonapplication/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で行います.
実際の動きはサンプルコードを使って説明します.

サンプルコード

post.html
<!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に追記ってやったほうがいいけどめんどくさかったから端折った)

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.parsefunction では,前半3行でクライアントへのレスポンス,
後半で./public/images/に保存されたファイルについて,エンコードされたファイル名から基のファイル名へとリネームを行っています.
filesが持つプロパティ,例えば基のファイル名はfiles.file._writeStream.pathといったように参照できます.

ひとこと

今日からNode.js days にもどるんるん.あ、あとjQuery Ajax で送った時も基本一緒です.

30
28
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
28