2018年7月31日火曜日

multer-s3を使ってaws S3へファイルアップロードする時の注意点(Node.js)


オフィス狛 技術部のHammarです。

今回もまた開発をしていく最中にちょっとハマったことについて書こうと思います。
今回は「ファイルアップロード」についてです。
よくあるファイルアップロードの機能ですが、ある条件のときにちょっとしたことなんだけどうまくいかずにハマりました。
まずファイルアップロード機能実装でやろうとしたことと、その環境をザックリ簡単に記します。

■やりたいこと

・AWS S3に動画ファイルをアップロード
・アップロードしたファイルをwebサイトで視聴できるようにする
・バックエンドのnode.jsにS3アップロードのAPIを作成する

■実装環境

・node.js(Express)
・multer-s3モジュールを利用

とりあえずS3にファイルアップロードするためのaws-sdkをインストールしたり、アップロード用のモジュールをもろもろインストールしますが、今回のハマったところはこの先なのでこの辺のインストール方法等は省略します。

さて、上記環境は整っている状態で実際にアップロード処理を作成します。
アップロード処理について今回は「multer-s3」というモジュールをつかって下記のように処理を書きました。 npmjs.comのサンプルの記載とほぼ同じ感じです。

■S3アップロード処理サンプル

var aws = require('aws-sdk')
var express = require('express')
var multer = require('multer')
var multerS3 = require('multer-s3')

var app = express()
var s3 = new aws.S3({ /* ... */ })

var upload = multer({
  storage: multerS3({
    s3: s3,
    bucket: 'some-bucket',
    metadata: function (req, file, cb) {
      cb(null, {fieldName: file.fieldname});
    },
    key: function (req, file, cb) {
      cb(null, ${req.body.fileName})
    }
  })
})

app.post('/upload', upload.array('photos', 3), function(req, res, next) {
  res.send('Successfully uploaded ' + req.files.length + ' files!')
})
上記をroutesディレクトリに任意のファイルを作成して記述します。

ここまでで基本的なアップロード機能は完成です。
で、実際に動かしてみます。今回アップロードしたときにそのファイル名とファイルIDも使いたかったので、requestのbodyにファイルとファイル名、ファイルのIDもつけて上記のAPIになげます。
動作の確認方法はいろいろあると思いますが、個人的にPostmanというツールを使ったほうが楽なのでこちらを使います。

■postmanでリクエスト作成

上記のような感じでリクエストを作成します。
  ①POSTを選択しAPIのURLを入力
  ②ファイルをアップロードするので「form-data」を選択
  ③アップロードするファイルと同時にリクエストするフィールド(key、value)を入力
  ④右上のsendボタンを押下
これで先ほど作成したAPIにリクエストが送られ、ファイルがアップロードされます。

で、ここからがハマったポイント
S3にファイルが上がっているか確認したところファイルは問題なく上がっています。ただ、なぜか②で一緒にbodyに記載していたファイル名やファイルIDがとれていない。そのためS3にアップロードしたファイル名が「undefined」となっています。アップロード自体はエラーとなっていませんでした。

    key: function (req, file, cb) {
      cb(null, ${req.body.fileName})
    }
上記のfileNameの部分でS3に上がったときのファイル名となる予定でしたが、なぜかfileNameがうまく取得できていないようです。
おかしい、同じbodyに入力していて、ファイルはアップロードできているのにファイル名がとれないなんて。。。

いろいろ調べてやってみても原因がわからず。。。
そこで最初のファイルがうまくいっているなら1番目の項目だけうまくいくのかと思い順番を下記のようにかえて再度アップロード。

なんと、ファイル名取れました!
ファイル自体もアップロードできている!
1番目も2番目の項目もうまくっているので1番目の項目だけってことではなさそうだけど、あれ?こんどはファイルIDが取れていない。
ということは、アップロードファイルより上の項目は取得できて、アップロードファイルより下の項目は取得できていないようです。

再度bodyの順番を下記のように並び替えてアップロードしてみます。
うまくいきました!
今度はファイル名、ファイルIDもちゃんと取れていました。

ということで、ファイルアップロード時のrequestのbodyはアップロードファイルの順番を最後にしておかないと、その他の項目が取得できないということがわかりました。

恐らく「multer-s3」というモジュールの特性や、記述の仕方もあるかもしれませんが、「multer-s3」でS3にアップロードするという実装に関しては上記のようなことが発生しますので注意が必要です。

またほかのnpmモジュールを使う際も少し注意したほうがよさそうで、「busboy」というモジュールも処理の組み方次第では同様の事象に注意が必要なようです。
multipartのアップロードストリームをYoutube投稿ストリームに受け流す

, ,

0 件のコメント:

コメントを投稿