AngularJSからexpressに画像をアップロードする

前提

要素 バージョン
node 7.4.0
npm 4.1.2
express 4.14.0
AngularJS 1.4.1

概要

  • AngularJSのページから画像ファイルをアップロードし、express側で保存させる
  • AngularJSには(少なくとも標準モジュールには)ファイルアップロードの仕組みが存在しないので、ディレクティブを自作して対応する

1.クライアントサイド

添付ファイルをモデルで扱うためのディレクティブを定義

app.directive('fileModel', ['$parse', function($parse) {
  return function(scope, element, attrs) {
    const model = $parse(attrs.fileModel);
    element.bind('change', function() {
      scope.$apply(() => {
        model.assign(scope, element[0].files[0]);
      });
    });
  };
}]);

上記ディレクティブは、以下のように利用する

<input type="file" name="myfile" file-model="my-file">

上記ディレクティブをinput[type=file]にバインドすることで、ファイル選択時にファイルの内容をAngularモデルにバインディングする。
これによって、添付されたファイルをAngularJSのモデルとして操作できるようになる。

ファイルアップロード用のサービスを定義

app.factory('fileUpload' , ['$http' , function($http) {
  return {
    upload(photo) {
      let formData = new FormData();
      formData.append('file' , photo);
      $http.post('/rest/photo/put', formData, {
        headers: {'Content-Type': undefined} ,
        transformRequest: null
      });
    },
  };
}]);

APIがあるであろう、’/rest/photo/put’に対して添付ファイルをPOSTする。
Content-Typeをundefinedに明示的に設定しておくと、AngularJS側で良い感じに設定してくれるので今回はおまかせする。
transformRequestをnullにしておかないと、POSTデータがJSONに変換される可能性があるので、一応明示的にNULLにしておく。

上記サービスを、添付ファイルを指定して実行することで、APIサーバに添付ファイルがPOSTされる

2.サーバサイド

Multerモジュールをインストール

Multerモジュールは、multipart/form-data形式のリクエストを扱うためのNodeJSのミドルウェア。これを用いることでexpress側で添付ファイルを処理することができる。

$ npm install --save multer

POSTされたファイルを保存する

Multerモジュールがインストールできたら、以下のコードをexpress側に追加する(※appはexpressオブジェクト)

var multer  = require('multer');
app.use(multer({ dest: './uploads/'}).any());

非常にシンプルだが、これだけで、アップロードファイルがPOSTされた際に、そのファイルを./uploadsに保存する処理が自動で行われる。

アップロードファイルの検証

アップロードされたファイルは、requestオブジェクトのfiles属性に含まれている。filesは配列であることから、複数ファイルの同時アップロードにも対応できる。

以下のコードでは、アップロードされたファイル(1件)の内容を出力し、無条件でsuccessを戻している。

app.post('/rest/photo/put' , function(req, res) {
  console.log(req.files[0]);
  res.send('success');
});

‘/rest/photo/put’に対して、画像ファイルを1件アップロードすると、以下のログが出力される

{ fieldname: 'file',
  originalname: '10.jpeg',
  encoding: '7bit',
  mimetype: 'image/jpeg',
  destination: './uploads/',
  filename: '652aa507d6e70b89e064bbddd3b33224',
  path: 'uploads/652aa507d6e70b89e064bbddd3b33224',
  size: 5297 }

ユニークなランダム文字列であるfilenameを含んだpathが既に出力に含まれているように、この時点で既に画像ファイルは保存されている。

もちろんファイル名を変更したり、保存する条件を指定したりもできるが、ここでは割愛する。

参考

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です