ExpressJS Multer: Upload image to server

2019-07-21 17:55发布

问题:

I'm newer with Node.js and Express.js.

I want to upload first a image into the server (directory: uploads/spots), and then (synchronous) upload the rest of form data in MongoDB.

I'm using REST (Method Post)

app.route('/spots').post(users.requiresLogin, spots.create);

and I'm using Multer for updating the image into the server, and works.

app.use(multer(
        { dest: './public/uploads/spots',
            onFileUploadStart: function (file) {
                var imagePath = file.path;

                gm(imagePath).resize(850, 850).quality(70).noProfile().write('public/uploads/spots/850x850/'+file.name, function (err) {
                    if (!err) {
                        gm(imagePath).resize(150, 150).quality(70).noProfile().write('public/uploads/spots/150x150/'+file.name, function (err) {
                            if (!err) {
                            }
                            else{
                                console.log('Error: '+err);
                            }

                        });
                    }
                    else{
                        console.log('Error: '+err);

                    }

                });

            }

        }));

Is working, but is asynchronous , and returns the response to frontend before that the image will be upload into the server.

My question is how to do this but synchronous and how to return the response to the frontend after that the image was uploaded.

Thank you!

spots.server.routes.js

'use strict';

module.exports = function(app) {
    var gm = require('gm');
    var multer  = require('multer');


    var users = require('../controllers/users.server.controller.js');
    var spots = require('../controllers/spots.server.controller.js');


    //Upload image
    app.use(multer(
        { dest: './public/uploads/spots',
            onFileUploadStart: function (file) {
                var imagePath = file.path;

                gm(imagePath).resize(850, 850).quality(70).noProfile().write('public/uploads/spots/850x850/'+file.name, function (err) {
                    if (!err) {
                        gm(imagePath).resize(150, 150).quality(70).noProfile().write('public/uploads/spots/150x150/'+file.name, function (err) {
                            if (!err) {
                            }
                            else{
                                console.log('Error: '+err);
                            }

                        });
                    }
                    else{
                        console.log('Error: '+err);

                    }

                });

            }

        }));



	// Spots Routes
	app.route('/spots')
		.get(spots.list)
		.post(users.requiresLogin, spots.create);

	app.route('/spots/:spotId')
		.get(spots.read)
		.put(users.requiresLogin, spots.update)
		.delete(users.requiresLogin, spots.hasAuthorization, spots.delete);

	// Finish by binding the Spot middleware
	app.param('spotId', spots.spotByID);
};

spots.server.controller.js (create method)

'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
	errorHandler = require('./errors.server.controller.js'),
	Spot = mongoose.model('Spot'),
	_ = require('lodash'),
    fs = require('fs');



/**
 * Create a Spot
 */
exports.create = function(req, res) {
	var spot = new Spot(JSON.parse(req.body.spot));
	spot.user = req.user;

    if(req.files.file)
        spot.image=req.files.file.name;
    else
        spot.image='default.jpg';


	spot.save(function(err) {
		if (err) {
            fs.unlinkSync('public/uploads/spots/'+spot.image);
            fs.unlinkSync('public/uploads/spots/850x850/'+spot.image);
            fs.unlinkSync('public/uploads/spots/150x150/'+spot.image);
			return res.status(400).send({
				message: errorHandler.getErrorMessage(err)
			});
		} else {
            var socketio = req.app.get('socketio'); // tacke out socket instance from the app container
            socketio.sockets.emit('spot.created.'+spot.municipality,  {spot:spot, user:req.user});
            socketio.sockets.emit('spot.created.'+spot.province,  {spot:spot, user:req.user});
            socketio.sockets.emit('spot.created.'+spot.community,  {spot:spot, user:req.user});
            socketio.sockets.emit('spot.created.'+spot.country,  {spot:spot, user:req.user});

            res.jsonp(spot);
		}
	});


};


/**
 * Spot authorization middleware
 */
exports.hasAuthorization = function(req, res, next) {
	if (req.spot.user.id !== req.user.id) {
		return res.status(403).send('User is not authorized');
	}
	next();
};

回答1:

The solution is not use onFileUploadStart method and use a function with callback in the controller.

routes

  // Spots Routes
    app.route('/spots')
    .get(spots.list)
    .post(users.requiresLogin,multer({ dest: './public/uploads/spots'}), spots.create);

controller

exports.create = function(req, res) {

if (req.files.file)
    exports.uploadImage(req.files.file,callback);
else
    callback();


    function callback(){
        var spot = new Spot(JSON.parse(req.body.spot));
        spot.user = req.user;

        if (req.files.file)
            spot.image = req.files.file.name;
        else
            spot.image = 'default.jpg';


        spot.save(function (err) {
            if (err) {
                fs.unlink('public/uploads/spots/850x850/'+spot.image);
                fs.unlink('public/uploads/spots/150x150/'+spot.image);
                return res.status(400).send({
                    message: errorHandler.getErrorMessage(err)
                });
            } else {
                var socketio = req.app.get('socketio'); // tacke out socket instance from the app container
                socketio.sockets.emit('spot.created.' + spot.municipality, {spot: spot, user: req.user});
                socketio.sockets.emit('spot.created.' + spot.province, {spot: spot, user: req.user});
                socketio.sockets.emit('spot.created.' + spot.community, {spot: spot, user: req.user});
                socketio.sockets.emit('spot.created.' + spot.country, {spot: spot, user: req.user});


                req.spot = spot;
                Feedback.subscribeSpot(req);

                Notify.getLocalSubscriptors(spot.municipality,spot.province,spot.community,spot.country,function(subscriptions){
                    Notify.create(req,null,spot,null,null,null,subscriptions,'spots/'+spot._id,false,'SPOT_CREATED', function(){
                        res.jsonp(spot);
                    });
                });
            }
        });
    }

};


exports.uploadImage = function(file, fn){
  var imagePath = file.path;

            gm(imagePath).resize(850, 850).quality(70).noProfile().write('public/uploads/spots/850x850/'+file.name, function (err) {
                if (!err) {
                    gm(imagePath).resize(150, 150).quality(70).noProfile().write('public/uploads/spots/150x150/'+file.name, function (err) {
                        if (!err) {
                          if(fn)fn();
                        }
                        else{
                            console.log('Error: '+err);
                        }

                    });
                }
                else{
                    console.log('Error: '+err);

                }

            });

};