web-dev-qa-db-ja.com

multerまたはbody-parserを使用してファイルをアップロードする方法

私はNodeJSの初心者で、「MongoDBとNodeJSを使用したWeb開発」という本に沿っています。私はその第6章で「multer」で立ち往生しています。ファイルのアップロードにmulterを使用すると、サーバーは次のエラーをスローします。

/Users/fk / Documents / imageuploader / node_modules / express / lib / application.js: 209
throw new TypeError('app.use() requires middleware functions'); ^

TypeError: app.use() requires middleware functions

しかし、bodyParserに置き換えるとサーバーが起動しますが、アップロードボタンをクリックすると、ブラウザに次のエラーが表示されます。

500 TypeError: Cannot read property 'file' of undefined

ただし、アップロードされたファイルが表示される別のページにリダイレクトされます。

BodyParserのコードは次のとおりです。サーバーの起動時に "body-parser deprecated"が表示されるため、正しく使用しているかどうかを確認してください。私は私のような他の質問を見ましたが、私は従いましたが、どれも実際に機能しません。

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));

app.use(bodyParser({
  uploadDir: path.join(__dirname, '../public/upload/temp')
}));

次のコードは、私がやるべきでないことがある場合に備えて、私がmulterをどのように使用するかを示しています。ファイル、ボディパーサー、またはミュータをアップロードする場合、どちらが良いでしょうか?

app.use(multer({
  dest: path.join(__dirname, '../public/upload/temp')
}));


var saveImage = function() {
  var possible = 'abcdefghijklmnopqrstuvwxyz0123456789',
    imgUrl = '';

  for (var i = 0; i < 6; i += 1) {
    imgUrl += possible.charAt(Math.floor(Math.random() * possible.length));
  }

  var tempPath = req.files.file.path,
    ext = path.extname(req.files.file.name).toLowerCase(),
    targetPath = path.resolve('./public/upload/' + imgUrl + ext);

  if (ext === '.png' || ext === '.jpg' || ext === '.jpeg' || ext === '.gif') {
    fs.rename(tempPath, targetPath, function(err) {
      if (err) throw err;
      res.redirect('/images/' + imgUrl);
    });
  } else {
    fs.unlink(tempPath, function() {
      if (err) throw err;

      res.json(500, {
        error: 'Only image files are allowed.'
      });
    });
  }
};
saveImage();

前のコードブロックは、ファイルのアップロードに使用しているロジックです。エラーでは、saveImage関数の次の行にある「file」を未定義として参照しています。パスを取得できないため、saveImage関数のelse部分に従ってエラー500がスローされます。ここで「ファイル」が未定義なのはなぜですか?わかりません。

var tempPath = req.files.file.path,
11
Farooq Khan

multer()は、指定した設定を使用するミドルウェアジェネレーターを返すため、戻り値をapp.use()に直接渡すことはできません。 documentation で生成できるミドルウェアのすべてのタイプを確認できますが、通常、生成されたミドルウェアは他のボディパーサーのようにグローバルではなくルートレベルで追加されます。これは通常、期待するファイルフィールドの名前を渡すためです。

たとえば、これは、フォームフィールド名がfooである単一のファイル(およびファイル以外のフィールド)を受け入れます。

var upload = multer({
  dest: path.join(__dirname, '../public/upload/temp')
});

// ...

app.post('/upload', upload.single('foo'), function(req, res) {
  if (req.file) {
    console.dir(req.file);
    return res.end('Thank you for the file');
  }
  res.end('Missing file');
});

また、body-parserは現在multipart/form-data対応ミドルウェアをエクスポートしないため、アップロードされたファイルの処理にそのモジュールを使用することはできません(application/x-www-form-urlencodedフォームでbase64エンコード文字列を渡す以外はまたは何か、しかしそれははるかに効率が悪いです)。

17
mscdex

MEANでのファイルアップロードの基本コードは次のとおりです。

HTML

<form id="frmDoc" name="frmDocument" ng-submit="upload()" class="form-horizontal form-bordered" enctype="multipart/form-data" >
        <fieldset>
            <div class="form-group">
                <label class="col-md-4 control-label" for="val_email">Document<span class="text-danger">*</span></label>
                <div class="col-md-4">
                    <div class="input-group">
                    <input type="file" name="file" id='file' required="required" />
                    </div>
                </div>
            </div>
        </fieldset>
        <div class="form-group form-actions">
            <div class="col-md-8 col-md-offset-4">
                <button type="submit" class="btn btn-sm btn-primary"><i class="fa fa-upload"></i> submit</button>
            </div>
        </div>
    </form>

クライアント側コード

app.controller ('myctrl',function($scope,$http){

  $scope.upload = function () {
            var file = angular.element(document.querySelector('#file')).prop("files")[0];
                $scope.files = [];
                $scope.files.Push(file);
                $http({
                    method: 'POST',
                    url: '/users/upload',
                    headers: { 'Content-Type': undefined },
                    transformRequest: function (data) {
                        var formData = new FormData();
                        formData.append('model', angular.toJson(data.model));
                        formData.append('file', data.files[0]);
                        return formData;
                    },
                    data: { model: { title: 'hello'}, files: $scope.files }

                }).success(function (res) {
                    console.log(res)
                });
        }


});

サーバーサイドコード

var multer  = require('multer');
var mkdirp = require('mkdirp');

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    //var code = JSON.parse(req.body.model).empCode;
    var dest = 'public/uploads/';
    mkdirp(dest, function (err) {
        if (err) cb(err, dest);
        else cb(null, dest);
    });
  },
  filename: function (req, file, cb) {
    cb(null, Date.now()+'-'+file.originalname);
  }
});

var upload = multer({ storage: storage });

router.post('/upload', upload.any(), function(req , res){
    console.log(req.body);
    res.send(req.files);
});
10
Ashutosh Jha