Node.js Express4-Multerでファイルアップロード

*ほしい機能がすぐに使える。あれも、これも。そう Node.jsならね*
#前置き
Node.js始めて3日目くらいの知識で書いています。
Express4以前の記事でファイルアップロードのコードを書いてもうまく動きません。
Express4ではMulterを使う必要があるようです。
以下記事は[本家](https://github.com/expressjs/multer)のドキュメントを参考に作成しました。
コードもほぼコピペです。

#Multerとは
multipart/form-dataを扱うためのミドルウェアです。

#インストール
`npm install multer`


#凡例

````js
var express = require('express')
var multer  = require('multer')

var app = express()
app.use(multer({ dest: './uploads/'}))
````
下記のようにフィールドやファイルオブジェクトにアクセスできます。

````js

console.log(req.body)
console.log(req.files)
````

#Multer ファイルオブジェクト

下記のフィールドを持つjsonオブジェクトが`request`オブジェクトにわたります。
`request.files`でアクセスします。

1.fieldname - HTMLフォームで指定された名前(`<input type=file name=uploadfile>`のname属性の値)
2.originalname - アップロードしたファイルのファイル名
3.name - アップロード時に勝手変更されたファイル名(この名前で保存される）
4.encoding - ファイルのエンコードタイプ
5.mimetype - ファイルのMime type
6.path - アップロードされたファイルのパス(サーバー側に保存されたファイルのパス）
7.extension - ファイルの拡張子
8.size - ファイルサイズ(byte)
9.truncated - サイズ制限によってファイルがtrancateされたかどうか
10.buffer - ファイルの生データ。inMemory オプションにtrueを指定しない限りはnull。
ちなみにinMemoryオプションをtrueにした場合、ファイルには保存されない。
ファイルがでかすぎるとOutOfMemoryが発生する。


#基本的な使い方

最低限必要なのはこれだけ。
ここでは保存先を指定する`dest`オプションだけを指定していますが、
他にもたくさんオプションがあります。(後述)

````js
app.use(multer({
  //uploadするフォルダ
  dest: './uploads/',

}))
````

アップロードしたファイルの情報はfilesに入っている

````upload.js
exports.post = function(req, res) {
      //この時点でアップロードされたファイルは`dest`で指定したパスに保存されている。
      console.log(req.files);
}

結果
{ thumbnail:
   { fieldname: 'thumbnail',
     originalname: 'hoge.txt',
     name: '1f56fee4b8b562a7ab7b1efb1959bdfb.txt',
     encoding: '7bit',
     mimetype: 'text/plain',
     path: 'uploads\\1f56fee4b8b562a7ab7b1efb1959bdfb.txt',
     extension: 'txt',
     size: 81115,
     truncated: false,
     buffer: null
 } 
}
````

#オプション
以下のオプションが用意されています。

dest
limits
includeEmptyFields
inMemory
rename(fieldname, filename, req, res)
changeDest(dest, req, res)
onFileUploadStart(file, req, res)
onFileUploadData(file, data, req, res)
onFileUploadComplete(file, req, res)
onParseStart()
onParseEnd(req, next)
onError()
onFileSizeLimit(file)
onFilesLimit()
onFieldsLimit()
onPartsLimit()

##dest
アップロードしたファイルの保存先
`dest: './uploads/'`

##limits
いろんな制限値を設定。下記種類がある。設定値はすべて数値
・`fieldNameSize` - ファイル名の最大長。デフォルトは100byte
・`fieldSize` - field valueの最大サイズ。デフォルトは1MB
・`fields` - ファイル以外のフィールドの最大数。デフォルトは無制限
・`fileSize` - アップロードするファイルの最大サイズ。デフォルトは無制限
・`files` - アップロードするファイルの最大数。デフォルトは無制限
・`parts` -　fields + files　の最大数。デフォルトは無制限
・`headerPairs` -  ヘッダの key=>value の組み合わせの値の最大数。デフォルトは2000

使い方

````js
limits: {
  fieldNameSize: 100,
  files: 2,
  fields: 5
}
````

##includeEmptyFields
空のフィールドが届いた場合に処理するかってことなか？
デフォルトはfalse

````js
includeEmptyFields: true
````
##putSingleFilesInArray
次のメジャーバージョンでは無くなるとのことなので、割愛

##inMemory
前述のとおり、trueを指定するとbufferにデータが保持され、ファイル保存されない。

##rename(fieldname, filename, req, res)
保存するファイル名を変更する場合はこれを使える。

````js
rename: function (fieldname, filename, req, res) {
  //このreturnした文字列がファイル名になる。ここで拡張子は含めない。
  return fieldname + filename + Date.now()
}
````

##changeDest(dest, req, res)
アップロードされるファイルの保存先を変更する場合はこちら。
受け取ったファイルの種類なんかでアップロード先を振り分けたいなんて場合はこれを使えばよさそうですね

使い方
````js
changeDest: function(dest, req, res) {
  //returnした文字列が保存先になります。
  return dest + '/user1'; 
}
````

##onFileUploadStart(file, req, res)
ファイルのアップロードが開始した際に発動
アップ状況を表示する場合なんかに使うんですかね

````js
onFileUploadStart: function (file, req, res) {
  console.log(file.fieldname + ' is starting ...')
}
````
return falseするとアップロードを止めることができます。

````js
onFileUploadStart: function (file, req, res) {
  if (file.originalname == 'virus.exe') return false;
}
````

##onFileUploadData(file, data, req, res)
データの受け取りが完了したら発動

````js
onFileUploadData: function (file, data, req, res) {
  //ファイルサイズとフィールド名をコンソールに表示
  console.log(data.length + ' of ' + file.fieldname + ' arrived')
}
````

##onFileUploadComplete(file, req, res
すべてが完了(ファイルの保存まで)したら発動

````js
onFileUploadComplete: function (file, req, res) {
  console.log(file.fieldname + ' uploaded to  ' + file.path)
}
````

##onParseStart()
フォームの解析が開始したら発動。どういうタイミングだかよくわかりません。

````js
onParseStart: function () {
  console.log('Form parsing started at: ', new Date())
}
````

##onParseEnd(req, next)
フォーム解析が完了したら発動。`reqest`オブジェクトと`next`オブジェクトが渡されます。

````js
onParseEnd: function (req, next) {
  console.log('Form parsing completed at: ', new Date());

  // usage example: custom body parse
  req.body = require('qs').parse(req.body);

  // call the next middleware
  next();
}
````

##onError()
何かしらのエラーが発生したら発動。`error`オブジェクトと`next`オブジェクトが渡されます。

````js
onError: function (error, next) {
  console.log(error)
  next(error)
}
````

##onFileSizeLimit()
`limits`オプションで指定したファイルサイズに達したら発動
これ以上のファイル受け取り処理は行われません。

````js
onFileSizeLimit: function (file) {
  console.log('Failed: ', file.originalname)
  //ここまで書き込んだファイルを削除
  fs.unlink('./' + file.path) // delete the partially written file
}
````

##onFilesLimit()
上記同様`limits`で制限したファイル数に達したら発動

##onFieldsLimit()
同上

##onPartsLimit()
同上

#受け取ったテキストファイルの内容をコンソールに表示してみるサンプル
以上を踏まえて、こんなコードを描いてみました。

````app.js
//省略・・・・
app.use(multer({
    dest:'./uploads',
    onFileUploadData:function(file, data, req, res){
        //dataはBufferオブジェクト。何も指定しないとutf-8でデコードされます。
        console.log(data.toString());
    }
})

//省略・・・・
````
アップロードするファイル

````hoget.txt
Hello Multer!!
````

これをアップロードすると、コンソールにHello Muter!!が表示されると思います。
データを格納しているBufferオブジェクトについては[ここを参照](https://nodejs.org/api/buffer.html)
処理の流れでいうと、この後にファイルが保存されます。
以上、すごく簡単なサンプルでした。

実際にはファイル送信後のroute先に`upload.js`とか作ってゴリゴリ処理するのでしょうが、
オプションのイベントハンドラ内だけでもある程度処理は可能です。


#ライセンス
MITライセンスです


#参考リンク
https://github.com/expressjs/multer