expressjs / multer

Node.js middleware for handling `multipart/form-data`.
MIT License
11.54k stars 1.05k forks source link

Multer diskStorage destination errors on production environment #655

Open acho999 opened 5 years ago

acho999 commented 5 years ago

Hello,

On development environment code below works properly but on production nothing works.When I opened logs there are this error: Error OccuredError: ENOENT: no such file or directory, open 'public/images/8c3f666974_kiwi.png'.2 days I am trying to resolve it but... no result I try many things read many articles but nothing ... What is the problem?I read all multer documentation and I think I am implementing it properly?

This is code:

const express = require("express");
const router = express.Router();
const multer = require('multer');
const db = require("../connection/databaseConn");
const Product = require("../models/Product");
const encryption = require("../encryption/encryption");
const path = require('path')

let storage;
let upload;

router.get("/upload",(req,res)=>{

    res.render("upload");

});

let imagesNames = [];

new Promise((resolve, reject)=>{
  resolve(
    storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null,"public/images/")
  },
  filename: function (req, file, cb) {

    let imageId = encryption.generateId();
    let imageNameWithId = imageId.substr(0,10);
    imagesNames.push({name:imageNameWithId,id:imageId});
    let fileName = "" + imageNameWithId + "_" + file.originalname;

    cb(null, fileName)
  }
}))

}).then((storage)=>{
  upload = multer({storage:storage}).any();
})

router.post('/upload', function(req, res) {

    upload(req, res, function(err) {

      if(err) {
        console.log('Error Occured' + err);
          return;
        }
        let files = req.files;

      Product.findById(req.session.productId).then((p)=>{
          for(let i = 0; i < files.length;i++){

            p.images.push({imageId:imagesNames[i].id,imageName :"/static/images/" + imagesNames[i].name + "_"  + files[i].originalname});

          }

          p.save();

      }).then(()=>{

            req.session.addMessage = "Product created!";
            res.redirect("/categoriesLoad");

       });
  })

});

module.exports = router;
LinusU commented 5 years ago

Does the directory public/images exist?

acho999 commented 5 years ago

Yes exist, images dir is in public dir.Now I change my code to this below, but now it gives me "Internal server error: http://s1356.photobucket.com/user/acho999/media/Internal%20server%20error_zpsrmx4heor.jpg.html?sort=3&o=0

But on development again everything is working.I have images on file system and in my product object.

const express = require("express");
const router = express.Router();
const multer = require('multer');
const db = require("../connection/databaseConn");
const Product = require("../models/Product");
const encryption = require("../encryption/encryption");
const path = require('path');

router.get("/upload",(req,res)=>{

    res.render("upload");

});

let imagesNames = [];

const multerConfig = {
  storage : multer.diskStorage({
    destination: function (req, file, next) {
      next(null,"public/images/")
    },
    filename: function (req, file, next) {

      let imageId = encryption.generateId();
      let imageNameWithId = imageId.substr(0,10);
      imagesNames.push({name:imageNameWithId,id:imageId});
      let fileName = "" + imageNameWithId + "_" + file.originalname;

      next(null, fileName)
    }
  })
};

router.post('/upload',multer(multerConfig).any(), function(req, res) {

      let files = req.files;

      Product.findById(req.session.productId).then((p)=>{
          for(let i = 0; i < files.length;i++){

            p.images.push({imageId:imagesNames[i].id,imageName :"/static/images/" + imagesNames[i].name + "_"  + files[i].originalname});

          }

          p.save();

      }).then(()=>{

            req.session.addMessage = "Product created!";
            res.redirect("/categoriesLoad");

       });

});

module.exports = router;
LinusU commented 5 years ago

next(null,"public/images/")

Could you try returning an absolute path here? Something like:

next(null, path.join(__dirname, 'public/images'))

acho999 commented 5 years ago

Hi, thanks for helping me! I try by this way but on development environment it gives me: Error: ENOENT: no such file or directory, open 'c:\Users\Angel\Documents\Наков\JSweb\NodeAndExpress\projects\project\routes\public\images\e1ada8c985_kiwi.png'

because directory public is in directory project.In path above it search public directory in routes directory, and that is wrong. In screenshot below on left side is my Upload.js file which is on routes dir and dirname returns path to this dir, an I think this is reason pathname not working in this case. http://s1356.photobucket.com/user/acho999/media/error_zpsysmzjizx.jpg.html. And there is my public dir and images dir (ignore dropzone files I don't use them). Without __dirname everything works on development.When I upload image it shows in images dir.But this is only on development, on production trows error.

LinusU commented 5 years ago

adjust the path to match relative to the file that holds the logic:

next(null, path.join(__dirname, '../public/images'))
acho999 commented 5 years ago

Thanks for suggestion, but again on development it works and on production return "Internal server error". As you can see on image below, in green color ,on left side, is image which I add on development environment in directory images: http://s1356.photobucket.com/user/acho999/media/dev-env_zpshjjtaivd.jpg.html. And as I wrote above on prod environment doesn't work... this is take me yet 5 days at least...

acho999 commented 5 years ago

Here is screenshot of heroku logs.On the bottom where is /upload path have error, quality is not very good: http://s1356.photobucket.com/user/acho999/media/logs_zps55htwmar.jpg.html

acho999 commented 5 years ago

This is error on /upload path, from heroku logs:

2018-10-03T14:29:07.566481+00:00 heroku[router]: at=info method=POST path="/upload" host=enigmatic-falls-17964.herokuapp.com request_id=74417b65-3e3d-4b70-941e-c3199325bf6c fwd="46.55.152.189" dyno=web.1 connect=0ms service=9884ms status=500 bytes=404 protocol=https 2018-10-03T14:29:07.565769+00:00 app[web.1]: Error: ENOENT: no such file or directory, open '/app/public/images/5a901a8328_IMG_20181003_142936.jpg'

leovazquezz1 commented 5 years ago

Same error. Any fix?

LinusU commented 5 years ago

Error: ENOENT: no such file or directory, open '/app/public/images/5a901a8328_IMG_20181003_142936.jpg'

This means that the directory /app/public/images doesn't exist, you have to create it prior to putting files in it...

khaled9544 commented 5 years ago

Same issue, did you figure it out?

khaled9544 commented 5 years ago

After research, in your case you can't upload images to the server because I think you are using server-less project so from the best practices upload your images to aws s3. please checkout the following https://www.freecodecamp.org/news/express-js-and-aws-lambda-a-serverless-love-story-7c77ba0eaa35/

hx-gh commented 3 years ago

Same issue. Did someone figured out?

sap-auto commented 3 years ago

Try using

destination: require.main?.path + "/" +" public/images/ "

(tested using "multer": "^1.4.2" , in typescript project)

militiwari commented 1 year ago

Using destination directly inside storage object without callback worked for me.

destination: path.join(__dirname, '../public/images'),

saksham2026 commented 8 months ago

destination: require.main?.path + "/" +" public/images/ "

This is working very well

erichutabarat commented 2 months ago

Try using

destination: require.main?.path + "/" +" public/images/ "

(tested using "multer": "^1.4.2" , in typescript project)

This works very well, thank you.